Unions and Tagged Unions

14.1 Bare Unions

const Value = union {
    int: i64,
    float: f64,
};
var v = Value{ .int = 42 };
v = Value{ .float = 3.14 };        // switch the active field by reassigning
// reading an inactive field is illegal behavior (checked in safe modes)

14.2 Tagged Unions (Sum Types)

With an explicit tag enum: union(MyTagEnum) { ... }.

Common uses: AST nodes, tokens, JSON values, messages, state machines.

const Shape = union(enum) {
    circle: f32,                              // radius
    rect: struct { w: f32, h: f32 },
    triangle: struct { a: f32, b: f32, c: f32 },
    point,                                    // void payload

    pub fn area(self: Shape) f32 {
        return switch (self) {
            .circle => |r| std.math.pi * r * r,
            .rect => |d| d.w * d.h,
            .triangle => |t| blk: {
                const s = (t.a + t.b + t.c) / 2;
                break :blk @sqrt(s * (s - t.a) * (s - t.b) * (s - t.c));
            },
            .point => 0,
        };
    }
};

var s: Shape = .{ .circle = 2 };
std.debug.print("{d}\n", .{s.area()});
switch (s) {
    .circle => |*r| r.* *= 2,                 // mutate the payload through a pointer capture
    else => {},
}
if (s == .circle) {}                          // compare against the tag
const tag = std.meta.activeTag(s);
_ = tag;

14.3 Extern and Packed Unions

extern union gives a C-compatible union. packed union gives a bit-level union (all fields share the same bits).