>I'd be interested in seeing a code comparison of equivalent Rust and Zig code with regards to tagged unions, to demonstrate your claim. I could help you with the Zig code if you provide the Rust code.
Well in Rust you don't have to define the enum and the union separately, actually in Rust unions and enums are effectively the same thing (outside of C FFI that is).
So you in Rust you have something like:
enum ComplexType {
Ok(u8),
NotOk,
}
Then to unpack it you always have to destructure it, you can't just do my_complex_type.Ok() or something like that. You can create accessor methods if that makes sense for your enum though, for instance for this ComplexType you could implement an "unwrap" function that returns the u8 in case of success and panics in case of an error. In general you tend to avoid those unless they really make sense, as a rule of thumb it's better to "match" the type (which seems similar to Zig's switch statement with enums).
Beyond that I dug a bit deeper in the docs and I don't quite understand how generics are supposed to work exactly, at first they look like what I'm used to in other languages but then I get to the generic printf example and I see this code:
pub fn printValue(self: *OutStream, value: var) !void {
const T = @typeOf(value);
if (@isInteger(T)) {
return self.printInt(T, value);
} else if (@isFloat(T)) {
return self.printFloat(T, value);
} else {
@compileError("Unable to print type '" ++ @typeName(T) ++ "'");
}
}
Is it just for the sake of the example or does it just exhibit a limitation of the generic system? What would happen if I wanted to be able to print a custom type for instance?
Also, if generics exist, why are things like "@clz" or "@intToFloat" compiler builtins, surely they could be implemented as part of the stdlib using a generic method? Although I see that "@memset" and "@memcpy" are also builtin and I can't quite figure out why so maybe I'm missing something here.