Docs/Types

Enums & tagged unions

A fixed set of values, or alternatives that carry data.

On this page

An enum is a fixed set of named values. A tagged union is a value that holds one of several types.

Define an enum#

Valk
enum Status { waiting, active, done }

fn main() {
    let status: Status = .waiting   // `.name` uses the expected type
    status = Status.active
    println(status)                 // active
    println(status == .active)      // true
    println(status.to(int))         // 1
}

Items are numbered from 0, and the first item is the default value. Items can be separated by commas or by spaces and new lines.

Give items a value#

Choose the item type after : and give each value in parentheses:

Valk
enum HttpStatus: u16 {
    ok (200)
    not_found (404)
}

enum Color: String {
    red ("#ff0000")
    blue ("#0000ff")
}

fn main() {
    println(HttpStatus.not_found.to(int)) // 404
    println(Color.red)                    // #ff0000
    println(Color.red.name())             // red
}

An enum only compares with values of the same enum: status == 0 is a compile error; convert first with .to(int).

Names and items#

Member Result
value.name() the item's name
value.to(String), "%value" the name, or the text for a String enum
Enum.items() every item, in declaration order
Enum.from_name(text) the item with that name; throws when there is none
Valk
enum Size { small, medium, large }

fn main() {
    each Size.items() as size {
        print(size.name() + " ")
    }
    println("")                                    // small medium large
    let parsed = Size.from_name("large") !? Size.small
    println(parsed)                                // large
}

Add methods#

Use extend to add methods and static functions to an enum:

Valk
enum Light { red, yellow, green }

extend Light {
    fn next() Light {
        return match this : Light {
            .red => .green
            .green => .yellow
            .yellow => .red
        }
    }
    static fn start() Light { return .red }
}

fn main() {
    let light = Light.start()
    println(light.next()) // green
}

Match on an enum#

A match that handles every item needs no default. Several items can share a case:

Valk
enum Day { mon, tue, wed, thu, fri, sat, sun }

fn kind(day: Day) String {
    return match day : String {
        .sat, .sun => "weekend"
        default => "weekday"
    }
}

fn main() {
    println(kind(.sun)) // weekend
    println(kind(.wed)) // weekday
}

See Control flow for patterns, ranges and guards.

Tagged unions#

A union lists the types a value can hold. Use match with as to get the value back as its own type:

Valk
union Setting : String | int | bool | null {}

fn display(value: Setting) String {
    return match value : String {
        String as text => text
        int as number => "number %number"
        bool as enabled => enabled ? "on" : "off"
        null => "unset"
    }
}

fn main() {
    let port: Setting = 8080
    println(display(port))          // number 8080
    println(display(true))          // on
    println(display(null))          // unset
}
  • When every type is handled, no default is needed.
  • null here is one of the alternatives. Write ?Setting for a union value that may be missing.
  • A tuple alternative is matched by its type: (String, int) as pair.

Inline unions#

For a one-off use, write the union directly as a type:

Valk
fn describe(value: String | int) String {
    return match value : String {
        String as text => "text: " + text
        int as number => "int: %number"
    }
}

fn main() {
    println(describe("hi")) // text: hi
    println(describe(3))    // int: 3
}

Recursive unions#

A named union can contain itself through a collection, which is useful for tree data:

Valk
union Tree : int | Array[Tree] {}

fn sum(tree: Tree) int {
    return match tree : int {
        int as leaf => leaf
        Array[Tree] as children => <{
            let total = 0
            each children as child : total += sum(child)
            return total
        }
    }
}

fn main() {
    let tree: Tree = Array[Tree]{ 1, Array[Tree]{ 2, 3 }, 4 }
    println(sum(tree)) // 10
}