const ComplexType = union(enum) {
Ok: u8,
NotOk,
};
It's recommended to use destructuring syntax to unpack it, but you have the option to use fields directly which invokes runtime safety checks.This matches the syntax for normal unions, which do not have tags, but still have runtime safety checks. Rust does not have this feature - unions must always have tags - where as in Zig the state that determines which tag is active in a union could be somewhere else.
> What would happen if I wanted to be able to print a custom type for instance?
const std = @import("std");
pub fn main() void {
const ComplexType = union(enum) {
Ok: u8,
NotOk,
};
var ct = ComplexType { .Ok = 123 };
std.debug.warn("{}\n", ct);
ct = ComplexType.NotOk;
std.debug.warn("{}\n", ct);
}
Outputs: ComplexType{ .Ok = 123 }
ComplexType{ .NotOk = void }
This is all implemented in userland in the standard library. Last time I checked, in Rust the equivalent code is implemented with a macro hard coded in the compiler.> why are things like "@clz" or "@intToFloat" compiler builtins, surely they could be implemented as part of the stdlib using a generic method?
They could be implemented in userland, but then they would possibly not lower to the LLVM primitives that they represent. In the case of the casting functions, it's more to do with semantics of the language, making it hard to accidentally shoot yourself in the foot. Shooting yourself in the foot on purpose, however, is always allowed.