Zooming out here a bit: I’m excited for the new Io. The approach to solving control flow virality (aka ‘function coloring’) is very promising, and it’s ok with me if minimum binary size regresses for a release or two because the team is focusing on getting that right.
I think yanking stuff out of posix the instant that Io is capable of delivering the functionality is hasty, but it’s minor. As long as the core team listens to feedback once 0.16 is official, we can recover the use cases which this development harms, while enjoying everything it brings to the table.
I’m talking about something which, so far as I know, has never been officially suggested as a solution to the consequences of having a hundred-plus member dispatch table. @LucasSantos91 brought it up and we’re riffing on it.
Call it “vtable shaking”. It’s a pretty good metaphor: most languages compile everything and then try to eliminate what isn’t in use, “tree shaking”, but Zig is different: it uses lazy compilation, so nothing is compiled unless it’s used, no tree shaking necessary.
The issue at hand: creating an Io instance counts as “using” every single function belonging to that dispatch table. When you say “put a struct instance in static memory containing a whole bunch of pointers to functions”, Zig just does that, and as a consequence, all those functions must be analyzed, compiled, and appear in the binary.
Lazy compilation means it won’t happen until or unless the struct is reached, which is what happens when an Io is created. But that’s as fine-grained as it gets, Zig doesn’t continue to hold off until fields from the struct are actually used, and late-bind a “real type” containing only those fields. One could think of that idea as: every struct, every union variant, starts with the default type void, and when it gets used, that is replaced with the user-specified type.
I don’t think Zig should do this! For one thing, the impact on the compiler would be fairly radical, and not in a good way. No composite type could be said to have a shape until semantic analysis is completed, that would introduce some pretty wild dependencies which would have to be carefully teased apart and made non-circular.
I also just don’t want to start having to think about data that way. If I tell the compiler that BlahStruct has a .wazoo field of u32, I don’t want it second-guessing that decision based on whether or not I’ve used it in reachable code. Too weird for me.
Another alternative: special case it. Put logic in the compiler which says “oh hey, this instance is Extra Special, it’s a struct consisting purely of restricted function pointers, we do as much devirtualization as possible and then shake the vtable to eliminate anything which wasn’t used, at the end”.
Much more plausible. But this is where I say: hey. c’mon. It’s time to stop pretending this thing is a struct. Let’s make it official and promote whatever-this-is into the type system.
It’s a mistake to think simplicity is achieved with as few concepts as possible. When we conflate several distinct concepts into one, none of the behavior goes away, it all has to be explained.
Example: are struct types containers? The answer is it depends because of tuples, which use the struct keyword but do not otherwise behave at all like structs. Separating the two concepts would simplify the language: both structs and tuples would be understood in terms of themselves, rather than tuples existing as a long list of exceptions to the general behavior of structs, which therefore ‘leaks’ onto structs, where it doesn’t belong. The answer to “are structs containers” is yes, the answer to “are tuples containers” is no, because the answer to “are tuples structs” is also no.
I think (and remember, this is a brainstorm, it’s not on the horizon as a proposal) that extra-special vtable-shaking behavior even being considered is a sign that we’re reaching the limits of the “roll your own interface” policy with Io, and we should be taking a good hard look at existing practice, and thinking about how to let the type system help us out. That’s what it’s there for.