# Tagged Unions

### Tagged Unions

A union is a value that may hold one of several types.

A tagged union combines a union with an enum tag. The tag says which field is active.

```zig
const Value = union(enum) {
    integer: i32,
    boolean: bool,
};
```

A `Value` may contain either an `i32` or a `bool`.

Create values with union literals:

```zig
const a = Value{ .integer = 123 };
const b = Value{ .boolean = true };
```

Each value stores both the data and the active tag.

A complete program:

```zig
const std = @import("std");

const Value = union(enum) {
    integer: i32,
    boolean: bool,
};

pub fn main() void {
    const a = Value{ .integer = 123 };
    const b = Value{ .boolean = true };

    std.debug.print("{}\n", .{a});
    std.debug.print("{}\n", .{b});
}
```

The output is:

```text
union(enum){ .integer = 123 }
union(enum){ .boolean = true }
```

Tagged unions are usually handled with `switch`.

```zig
const std = @import("std");

const Value = union(enum) {
    integer: i32,
    boolean: bool,
};

fn print(value: Value) void {
    switch (value) {
        .integer => |n| {
            std.debug.print("integer: {d}\n", .{n});
        },
        .boolean => |b| {
            std.debug.print("boolean: {}\n", .{b});
        },
    }
}

pub fn main() void {
    print(Value{ .integer = 42 });
    print(Value{ .boolean = false });
}
```

The output is:

```text
integer: 42
boolean: false
```

The syntax:

```zig
.integer => |n|
```

means:

1. Match the `.integer` case.
2. Extract the payload value.
3. Bind it to the name `n`.

The extracted value has the correct type.

In:

```zig
.integer => |n|
```

`n` has type `i32`.

In:

```zig
.boolean => |b|
```

`b` has type `bool`.

A tagged union is similar to this pair:

```zig
const Tag = enum {
    integer,
    boolean,
};
```

plus:

```zig
const Value = struct {
    tag: Tag,
    ...
};
```

but Zig combines them into one checked type.

The compiler prevents reading the wrong field.

```zig
const value = Value{ .integer = 10 };

const b = value.boolean;
```

This is invalid because the active field is `.integer`, not `.boolean`.

Zig checks this at runtime in safe builds.

A tagged union may be switched without extracting the payload.

```zig
switch (value) {
    .integer => {
        std.debug.print("integer\n", .{});
    },
    .boolean => {
        std.debug.print("boolean\n", .{});
    },
}
```

Sometimes only the tag matters.

The tag itself may be obtained with `std.meta.activeTag`.

```zig
const std = @import("std");

const Value = union(enum) {
    integer: i32,
    boolean: bool,
};

pub fn main() void {
    const value = Value{ .integer = 99 };

    const tag = std.meta.activeTag(value);

    std.debug.print("{}\n", .{tag});
}
```

The output is:

```text
.integer
```

A tagged union may use an explicit enum type.

```zig
const Kind = enum {
    integer,
    boolean,
};

const Value = union(Kind) {
    integer: i32,
    boolean: bool,
};
```

This is useful when the tag type is needed elsewhere in the program.

Tagged unions are common in parsers.

```zig
const Token = union(enum) {
    identifier: []const u8,
    number: i64,
    plus,
    minus,
    eof,
};
```

Some variants carry data. Others do not.

Values without payloads are written as:

```zig
const t = Token.plus;
```

Payload variants use a union literal:

```zig
const t = Token{
    .number = 123,
};
```

A parser may process tokens like this:

```zig
switch (token) {
    .identifier => |name| {
        std.debug.print("identifier: {s}\n", .{name});
    },
    .number => |n| {
        std.debug.print("number: {d}\n", .{n});
    },
    .plus => {
        std.debug.print("+\n", .{});
    },
    .minus => {
        std.debug.print("-\n", .{});
    },
    .eof => {
        std.debug.print("eof\n", .{});
    },
}
```

Tagged unions are also useful for syntax trees.

```zig
const Expr = union(enum) {
    integer: i64,

    add: struct {
        left: *Expr,
        right: *Expr,
    },

    subtract: struct {
        left: *Expr,
        right: *Expr,
    },
};
```

Each variant represents one form of expression.

A tagged union stores only one active payload at a time. Its size is large enough for the largest field plus the tag.

A plain `union` has no safety tag.

```zig
const Bits = union {
    i: i32,
    f: f32,
};
```

Plain unions are mainly for low-level memory work. Most application code should use tagged unions.

Tagged unions are one of Zig's most important data modeling tools. They replace many uses of inheritance hierarchies and manual tag fields found in C and C++ programs.

Exercises.

7-17. Define a tagged union `Shape` with variants `circle` and `rectangle`.

7-18. Define a tagged union `Token` with variants `number`, `identifier`, and `eof`.

7-19. Write a function that switches on a tagged union and prints different messages for each variant.

7-20. Define a tagged union where one variant has no payload and another variant stores a struct.

