# Enums

### Enums

An `enum` is a type whose value must be one item from a fixed list.

Use an enum when a value has a small number of named choices.

For example, a traffic light can be red, yellow, or green:

```zig
const TrafficLight = enum {
    red,
    yellow,
    green,
};
```

This defines a new type named `TrafficLight`.

A value of this type can only be one of these:

```zig
TrafficLight.red
TrafficLight.yellow
TrafficLight.green
```

It cannot be some random string or number.

#### Creating Enum Values

You can create an enum value by writing the enum type, a dot, and the tag name:

```zig
const light = TrafficLight.red;
```

Here, `light` has the value `red`.

When the expected type is already known, Zig lets you use a shorter form:

```zig
const light: TrafficLight = .red;
```

The type annotation tells Zig that `.red` means `TrafficLight.red`.

This shorter style is common in Zig.

#### Why Enums Are Useful

Without enums, you might write code like this:

```zig
const status = 2;
```

But what does `2` mean?

Does it mean active? Failed? Pending? Closed?

An enum gives the value a name:

```zig
const Status = enum {
    pending,
    active,
    failed,
    closed,
};

const status = Status.active;
```

Now the code explains itself.

The compiler also checks that you only use valid values.

#### Switching on an Enum

Enums work well with `switch`.

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

const Status = enum {
    pending,
    active,
    failed,
    closed,
};

pub fn main() void {
    const status: Status = .active;

    switch (status) {
        .pending => std.debug.print("pending\n", .{}),
        .active => std.debug.print("active\n", .{}),
        .failed => std.debug.print("failed\n", .{}),
        .closed => std.debug.print("closed\n", .{}),
    }
}
```

Output:

```text
active
```

The switch handles every possible enum tag.

That is one of the main benefits. If you later add a new enum tag, Zig can force you to update the switch.

#### Exhaustive Switches

An exhaustive switch handles every possible value.

```zig
switch (status) {
    .pending => {},
    .active => {},
    .failed => {},
    .closed => {},
}
```

Because `Status` has exactly four possible values, the switch must cover all four.

This is safer than using loose integers or strings. The compiler knows the full list of possible values.

You can also use `else`:

```zig
switch (status) {
    .active => std.debug.print("active\n", .{}),
    else => std.debug.print("not active\n", .{}),
}
```

Use `else` when you really want to group the remaining cases together. For important state machines, explicit cases are usually better.

#### Enum Methods

Like structs, enums can contain functions.

```zig
const Direction = enum {
    north,
    south,
    east,
    west,

    fn isVertical(self: Direction) bool {
        return switch (self) {
            .north, .south => true,
            .east, .west => false,
        };
    }
};
```

Use it like this:

```zig
const d: Direction = .north;
const vertical = d.isVertical();
```

The method receives `self: Direction`.

This works the same way as struct methods. The call:

```zig
d.isVertical()
```

is shorthand for:

```zig
Direction.isVertical(d)
```

#### A Complete Enum Example

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

const Direction = enum {
    north,
    south,
    east,
    west,

    fn opposite(self: Direction) Direction {
        return switch (self) {
            .north => .south,
            .south => .north,
            .east => .west,
            .west => .east,
        };
    }
};

pub fn main() void {
    const d: Direction = .north;
    const other = d.opposite();

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

This prints the opposite direction.

The important part is this method:

```zig
fn opposite(self: Direction) Direction {
    return switch (self) {
        .north => .south,
        .south => .north,
        .east => .west,
        .west => .east,
    };
}
```

It takes one `Direction` and returns another `Direction`.

#### Enum Values Are Not Strings

This enum tag:

```zig
.red
```

is not the string `"red"`.

It is a typed enum value.

That means this is wrong:

```zig
const color: Color = "red"; // error
```

You must use the enum tag:

```zig
const color: Color = .red;
```

This distinction matters. Strings are text. Enums are fixed symbolic values known to the compiler.

#### Enum Values Are Not Plain Integers

Enums may have integer representations internally, but you should not treat them as plain integers in normal code.

This is the right style:

```zig
const mode: Mode = .read;
```

This is usually the wrong style:

```zig
const mode = 0;
```

The second version loses meaning and type safety.

When you need explicit integer values, Zig supports that too.

#### Enums with Explicit Integer Values

You can choose the integer tag type:

```zig
const HttpStatus = enum(u16) {
    ok = 200,
    not_found = 404,
    internal_server_error = 500,
};
```

Here, the enum uses `u16` as its tag type.

Each tag has a numeric value:

```text
ok = 200
not_found = 404
internal_server_error = 500
```

This is useful when the numbers are part of an external format, protocol, ABI, or file format.

Example:

```zig
const status: HttpStatus = .not_found;
```

The enum value is still not just a raw `u16`. It is an `HttpStatus`.

#### Converting Enums to Integers

You can convert an enum value to its integer tag with `@intFromEnum`.

```zig
const code = @intFromEnum(HttpStatus.not_found);
```

Now `code` is `404`.

Complete example:

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

const HttpStatus = enum(u16) {
    ok = 200,
    not_found = 404,
    internal_server_error = 500,
};

pub fn main() void {
    const status: HttpStatus = .not_found;
    const code = @intFromEnum(status);

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

Output:

```text
code = 404
```

Use this when you need the numeric representation.

#### Converting Integers to Enums

Converting an integer to an enum is more delicate.

The integer may not match a valid enum tag.

For example, this enum only allows three values:

```zig
const Color = enum(u8) {
    red = 1,
    green = 2,
    blue = 3,
};
```

The integer `9` is not a valid `Color`.

Zig provides tools for this kind of conversion, but you must be careful because not every integer is valid. In beginner code, avoid converting raw integers into enums unless you are parsing external data and validating it carefully.

A safer design is often to parse with a `switch`:

```zig
fn colorFromByte(byte: u8) ?Color {
    return switch (byte) {
        1 => .red,
        2 => .green,
        3 => .blue,
        else => null,
    };
}
```

Now the function returns `?Color`.

That means: either a valid `Color`, or `null`.

#### Enum Literals

A value like this is an enum literal:

```zig
.red
```

It does not name the enum type directly.

So Zig needs context.

This works:

```zig
const color: Color = .red;
```

The type annotation provides the context.

This also works:

```zig
fn paint(color: Color) void {
    _ = color;
}

paint(.red);
```

The function parameter tells Zig that `.red` means `Color.red`.

But this does not work by itself:

```zig
const x = .red; // not enough type information
```

Zig does not know which enum type `.red` belongs to.

#### Enums as State

Enums are excellent for representing state.

```zig
const ConnectionState = enum {
    disconnected,
    connecting,
    connected,
    closing,
};
```

Then code can use a switch:

```zig
fn canSend(state: ConnectionState) bool {
    return switch (state) {
        .disconnected => false,
        .connecting => false,
        .connected => true,
        .closing => false,
    };
}
```

This is clearer than using integers:

```zig
0 = disconnected
1 = connecting
2 = connected
3 = closing
```

The enum names carry the meaning.

#### Enums as Modes

Enums are also good for mode selection.

```zig
const OpenMode = enum {
    read,
    write,
    append,
};
```

A function can accept the enum:

```zig
fn openFile(path: []const u8, mode: OpenMode) void {
    _ = path;

    switch (mode) {
        .read => {},
        .write => {},
        .append => {},
    }
}
```

The call is clear:

```zig
openFile("data.txt", .read);
```

The function signature tells Zig that `.read` is an `OpenMode`.

#### Common Mistake: Using Strings for Fixed Choices

Beginners often reach for strings:

```zig
const mode = "read";
```

This is flexible, but too flexible.

The compiler cannot stop you from writing:

```zig
const mode = "raed";
```

That typo is just another string.

With an enum:

```zig
const mode: OpenMode = .read;
```

A typo becomes a compile error:

```zig
const mode: OpenMode = .raed; // error
```

Use enums when the choices are known ahead of time.

#### Common Mistake: Adding `else` Too Early

This works:

```zig
switch (state) {
    .connected => true,
    else => false,
}
```

But it may hide future mistakes.

Suppose you later add a new state:

```zig
const ConnectionState = enum {
    disconnected,
    connecting,
    connected,
    closing,
    reconnecting,
};
```

The `else` branch will silently handle `.reconnecting`.

That may or may not be what you want.

For important logic, prefer explicit cases:

```zig
switch (state) {
    .disconnected => false,
    .connecting => false,
    .connected => true,
    .closing => false,
    .reconnecting => false,
}
```

Now the compiler helps you when the enum changes.

#### The Main Idea

An enum defines a fixed set of named choices.

```zig
const Status = enum {
    pending,
    active,
    failed,
    closed,
};
```

A value of this type must be one of those choices:

```zig
const status: Status = .active;
```

Use enums for states, modes, categories, commands, directions, result kinds, and any case where a value should come from a known list. Enums make invalid states harder to write and valid states easier to read.

