Can we have compile-time, zero cost interfaces?

I agree, I think this wouldn’t be possible, it would probably imply that the compiler would have to create union types under the hood, to accommodate different types that share that interface, but it’s against zig principles, not zero-cost, and way beyond the kind of interfaces that are discussed here.

To have that, you could still create union types yourself though, I think.

1 Like

Yea for sure. I’m not really a fan of multiple interfaces (kinda reminds me of multiple inheritance as well), and it quickly makes the code unreadable (I know this is a similar idea to Rust traits but without us allowing actual function implementation within the interface itself). I also went with the initial solution as a way to have a simple solution that would still fit in within our current design, while also reducing performance costs, aiming for a compile time only solution). With the original one the syntax can stay as is. The struct “implements interface” syntax already looks a bit stressful haha (although I know it’s same syntax as tagged unions. But the implications are deeper. Although I’m happy you typed it out so it can help us better “feel” what we are proposing or not proposing.

But I’m confident that we can come up with a simple direct solution to expressing intent through anytype, still get compile time interfaces, but provide syntactic sugar for them, so no vtable or dynamic dispatch is required. It really just us moving the anytype function signatures into its own namespace “interface” and then just checking that the type being passed in (during compile time) has a function matching that signature.

It solves the contract part, which is the most important part for me.

The other part of what I use interfaces for could be created in user space. I can live with having a library that code generates the vtables and type erased structs allowing me to make lists of interfaces.

2 Likes

Yeah, I agree. What they are describing here is basically C++'s concepts who are purely a compile time thing.

I think it matters to clearly lay out that interfaces/traits have two important benefits with very different underlying implementations:

  1. Comptime template/anytype constraints
  2. Runtime polymorphism with dynamic dispatch

They are both very useful. But they can become conflated and entangled with each other, since generally you’d want the same interface or trait declaration to fill both roles, rather than writing a separate but identical type description for either one.

Anyway, I’d very much like to see both supported as a language feature. Just anytype on its own is not adequate for the comptime case since it doesn’t clearly communicate the contract of a function, i.e. what the passed argument is actually expected to be. And maintaining dynamic dispatch as a library feature without language support sounds like a recipe for a lot of nasty headaches.

1 Like