One halfway option in Zig (though I _think_ interfaces are still being considered for addition to the language as first-class citizens) is to use the language's metaprogramming facilities.
Somebody, once, in the userspace of the language, needs to write a utility that reads a type and produces an interface checker for that type, so that you're able to write code like the following:
const IDog = Checker(TemplateDogType);
Then you can use that when defining a function expecting to conform to some interface: fn bark(_dog: anytype) void {
const dog: IDog(_dog) = _dog;
dog.bark();
}
You can easily get nice compiler errors, no runtime overhead, and all the usual sorts of things you expect from a simple interface system. It's just more verbose.Limiting access to non-interface methods without runtime overhead would be a bit more cumbersome I think. Off the top of my head, the following API is possible though:
fn bark(dog: anytype) void {
IDog.bark(&dog);
}