The docs for comptime contains pretty much everything you need to know, read this first: Documentation - The Zig Programming Language.
comptime is relevant to traits / interfaces because it is the mechanism behind static dispatch. If you want to write generic code right now in Zig, you just write a function that accepts a type as one of its parameters, then refer to that type either in the type of other parameter(s) or as the return type:
// types are also just values that are compile-time known
fn add(comptime T: type, a: T, b: T) T {
return a + b;
}
One important concept that makes comptime make more sense is that Zig’s compiler is lazy. It does not analyze functions, declarations, or anything that your program doesn’t use, so it doesn’t care, for example, that add(bool, true, false)
would cause an error. Only if you actually invoked such a function call, would it then analyze the function given T=bool
, and report an error.
This means that zig’s generics is basically compile-time duck typing.
We can enforce type constraints similar to traits by ourselves to give the user a more informative error message if their type is wrong. This is achieved by comptime
assertions like so:
fn add(comptime T: type, a: T, b: T) T {
comptime {
// all code in this scope is interpreted at compile-time.
// @typeInfo is the builtin function which provides type reflection.
// This is a very simple example, we can do much deeper inspection if we wanted.
switch (@typeInfo(T)) {
.int, .float => {},
// If T is a numerical type, the compiler won't even look at this branch,
// so it won't cause a compile error. Again, the compiler is *lazy*.
else => @compileError("Can only add ints or floats!"),
}
}
return a + b;
}
I’ll also showcase anytype
, since its sometimes used instead of passing a separate type
parameter, but it can’t do anything the previous method can’t also do.
// anytype allows generics without an explicitly named T
fn add(a: anytype, b: @TypeOf(a)) @TypeOf(a) {
return a + b;
}
There is also the separate problem of dynamic/runtime dispatch, which is usually what “interfaces” refers to, this is unrelated to comptime and is achieved via function pointers/vtables.