I wrote a post about using mixins in Zig here and I am hoping to get your opinion on the post and more importantly on the described mixin pattern.
One downside to these kind of solutions is that they generate a lot of code when compiled, because now the compiler is copying that code for you.
It isn’t any different for the current reader interface as that too will generate an instance for each new type given.
Might be good to note that only versions used in the final program will end up in codegen as zig is lazy and won’t even pass those definitions through semantic analysis iirc unless they’re used. It’s then up to LLVM to dedupe those that make it past sema.
So it’s not as bad as that part makes it out to be.
@igors84 I really appreciate the writeup on mixins! A few random thoughts:
What are the pros and cons of this mixin pattern vs. interfaces using vtable-based runtime dispatch? I guess the latter allows the interface to take user-provided implementations (like Allocators, for example). I would be really interested in hearing your thoughts about the suitability of each approach for different problems.
In Zig you can’t mix in additional fields only functions and consts,
It is actually possible to create fields programmatically by using the @Type() builtin. Maybe that could be combined with mixins for some interesting effects.
What’s your favorite use of mixins in the Zig standard library? Looks like there are some interesting things in there.
Those are some great question and probably a whole post could be written about them but here are some of my thoughts.
I don’t see mixins as replacement for vtable interfaces. Each has its own place. For allocators interface has more sense since all allocators can easily fit under a common interface. On the other hand both
net.Stream support reading and writing but only the File also supports seeking. We could make an interface that has it all but for
net.Stream the seek methods could just return some
NotSupported error but mixins can provide only the methods that are really supported. I am told vtable interface is also incompatible with async.
On the other hand mixins solve a number of issues that has nothing to do with interfaces. One only needs to look for
usingnamespace through zig source code to see some interesting examples like:
- Supporting some operations only for some types of generic parameter here.
- Providing common functionality for a set of structs that have the same fields in different order or slightly different type here.
- Provide wrapping functionality only if the thing that is wrapped supports it like here.
- Allow some complex meta data generation like this .