Sum types & match

Model data with tagged unions and dispatch exhaustively with match.

An enum whose variants carry payloads is a tagged union (sum type): a value is exactly one variant at a time, tracked by a hidden discriminant. This is the idiomatic way to model ASTs, IRs, and state machines. Recursive shapes use a pointer.

enum Expr {
    Lit(i64),
    Add(Expr*, Expr*),
    Neg(Expr*),
    Nil                      // a unit variant (no payload)
}

Constructing and matching

Construct with EnumName.Variant(args) (or just EnumName.Variant for unit variants). Dispatch with match, which binds each variant’s payload to fresh locals scoped to the arm.

fun eval(Expr* e) -> i64 {
    Expr node
    unsafe { node = ~e }
    match node {
        Lit(v)    => return v
        Add(l, r) => return eval(l) + eval(r)
        Neg(x)    => return 0 - eval(x)
        Nil       => return 0
    }
    return 0
}

Rules

  • match is exhaustive: cover every variant, or add a _ arm.
  • A payload variant is laid out as an aggregate of a tag plus its payload, passed and returned by value like a struct. Use a pointer (Expr*) for recursive occurrences.
  • MVP payloads are scalars, pointers, text, and enums up to 8 bytes each; wrap larger aggregates in a pointer.
  • Plain C-style enums (enum Status : i32, no payloads) are unchanged.
  • An exported sum type is fully usable across modules — importers can construct its variants and match on it.

Why it matters

Sum types make illegal states unrepresentable and pair with match to force you to handle every case, all with zero runtime type information.

Next: Generics & slices.