Enums

Enums in Cyrus are a way to define a type that can hold one value out of a fixed set of variants. Each variant can be a simple tag, a tagged constant, or carry additional fields (like a struct).


Declaring an Enum

You declare an enum with the enum keyword, followed by its name and variant list:

enum Color {
    Red,
    Green,
    Black,
    Valued = "my valued color!",
    Custom(int, int, int)
}

Using Enums

You construct enum values by qualifying them with the enum's name:

#variant = Color.Red;
#variant = Color.Valued;
#variant = Color.Custom(1, 2, 3);

Matching Enum Variants

The switch statement lets you match a value against the possible variants of an enum. Each case corresponds to one variant. If the variant carries fields, you can bind them to local variables inside the case body:

switch (variant) {
    case .Red:
        printf("Red\n");
        break;
    case .Black:
        printf("Black\n");
        break;
    case .Valued:
        printf("Valued\n");
        break;
    case .Custom(a, b, c):
        printf("Color(%d, %d, %d)\n", a, b, c);
        break;
    default:
        printf("Unknown\n");
        break;
}

Fallthrough into Enum Variants with Fields

When a case without fields falls through into a case with fields, the compiler must attempt to bind payload variables for the second case. Since the actual variant does not contain those fields, the bindings would be undefined, which could lead to undefined behavior at runtime.

The compiler will not allow this. If a programmer attempts to write a switch where a fieldless case falls through into a case with fields, the compiler will produce an error, forcing the developer to either terminate the first case with break; or explicitly handle fallthrough safely.

 switch (variant) {
    case .Red:
        printf("Red chosen!\n");
        // missing `break;`
    case .Custom(a, b, c):
        printf("Custom(%d, %d, %d)\n", a, b, c);
        break;
}