3 ms·
Aw, I get that this is just showing off use cases for the new inline else feature, but from the title I was hoping it had more to do with this issue[0]. Having
by losvedir 4y ago
Aw, I get that this is just showing off use cases for the new inline else feature, but from the title I was hoping it had more to do with this issue[0]. Having only used Zig enough for an Advent of Code, interfaces via a mechanism akin to rust's traits is probably my highest wishlist feature.
If I understand the post here correctly, the version of interfaces shown affects the runtime data representation. And tagged unions have to be at least the size of the largest variant, sometimes plus the tag (right? Or is that just true in rust?).
Ideally, to me, an "interface" can be used as purely a compile time constraint. With rust traits, to use the example in the post, when you define a function that takes an "Animal", it will basically generate a version of the function that takes a Cat, and one that takes a Dog, and double checks that Cat and Dog both have `talk` implementations. So the tradeoff is you get static dispatch with no wasted space in the data representation, at a cost of more code generation.
Zig's comptime is powerful enough, that you can maybe even implement this version of traits in "userland" code, and that linked issue has some neat examples, though I think it would be better in the compiler itself so it can more easily be used throughout the ecosystem and so it interacts better with tooling (e.g. doc generation).
[0] https://github.com/ziglang/zig/issues/1268 https://github.com/ziglang/zig/issues/1268
- kristoff_it 4y ago> And tagged unions have to be at least the size of the largest variant, sometimes plus the tag (right? Or is that just true in rust?). That's correct. If you have wildly different sizes, you can create a union of pointers. It will require you to manage the memory for the concrete implementation separately, but this way you will not waste space. const Foo = union(enum) { dog: *Dog, cat: *Cat, // ... }; > With rust traits, to use the example in the post, when you define a function that takes an "Animal", it will basically generate a version of the function that takes a Cat, and one that takes a Dog, and double checks that Cat and Dog both have `talk` implementations. So the tradeoff is you get static dispatch with no wasted space in the data representation, at a cost of more code generation. Yes, that post is specifically about the need for dynamic dispatch, in Zig you can get monomorphization like so: fn makeAnimalTalk(animal: anytype) void { // optionally use some metaprogramming to validate `animal` // and produce a custom compile error when the trait is not // fulfilled. animal.talk(); // will work on any type that can be used like that }