something I'd like to not port over from our current implementation is tag union optimizations other than the specific case of single-tag unions getting unwrapped
the reason for this is that tag unions which compile to a normal tagged union are very straightforward to generate glue for, whereas right now tag unions are super hard to generate glue for because we have around 4 or 5 completely different representations we compile to
at the time we didn't realize what effect they would have on glue (glue didn't actually exist at the time) but now with the benefit of hindsight I think they're not worth it
What is the plan for recursive tags?
they have to be nominal
those are different - in that case it's not an optimization, we just have to do special heap stuff unavoidably
I would have to relook over the tag types, but I think this makes sense. I think most of the complex forms relate to recursive tags anyway.
I assume we would make all tags be equivalent (enough bytes for all fields with max field alignment, tag id)
. If there are no fields, this would become only tag id
.
And the only exception is single tags which are represented as the underlying type.
yep!
what about box? Make it a bespoke builtin type?
yeah just like today
I think it is currently the main (only?) use of NonNullableWrapped tags
today, box is actually a tag, not a standalone type.
ha, TIL!
yeah I think it should be standalone
doesn't it need special semantics when you put a closure in it? :thinking:
maybe that has never worked, which would explain the problems with trying to pass Box
ed closures to the host :sweat_smile:
I don't think boxed closures work today
that representation would certainly explain why!
Yeah, from looking at the tag variants, we have:
NonNullableUnwrapped
.Unwrapped means you don't need a tag id (either only one variant or two variants with one being null)
and Nullable meaning it can be null
I'm sure these matter for classic cons lists. I'm not sure how much they matter for other structures. I would assume a tree that instead of using lists uses a specific number of nodes in a tag could gain value from some of these patterns, but not sure that really matters for normal roc code. Recursive tags are pretty rare in roc due to the basis being flat lists
If we were to keep any of these optimization, I think we would only want to keep tagged pointers if we have less than N tags. That is likely to make a meaningful perf impact due to being able to check the tag id without following a pointer indirection. I don't think any of the other changes would have significant gains over that.
Also, are we planning to allow recursive types without tags? Like Node a: List (U64, Node a)
Totally fine if it requires being nominal, but I think that is a common annoying case to hit in the current compiler.
no, Ayaz wrote a thing (I forget where) about how they cause a big problem
and the best solution seems to be disallowing them
that was the main motivation for replacing opaque types with custom tag unions
(well, the original motivation)
so that we could still have recursive sum types that could be passed to the host (which opaque types can't)
anyway, we can always reintroduce some number of these in the future if we want to, but right now I think it's way more important to get reliable, working glue
This:
Richard Feldman: no, Ayaz wrote a thing (I forget where) about how they cause a big problem
Richard Feldman: and the best solution seems to be disallowing them
Is in response to this?
Also, are we planning to allow recursive types without tags? Like
Node a: List (U64, Node a)
correct?
If so, what would the equivalent look like with nominal types?
Last updated: Jul 06 2025 at 12:14 UTC