Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Enums

An enum is a type that holds exactly one of several named variants. Each variant may carry a payload (zero or more fields). Enums give you tagged unions: a value knows which variant it is, and pattern matching lets you recover the payload safely.

Declaration

Enums are declared with is enum { ... }. Each variant is a name, optionally followed by a parenthesized list of payload types:

Result is enum {
  Ok(i64)
  Err(buf)
}
Range is enum {
  Empty
  Bounded(i64 i64)
}

Empty is a nullary variant — it carries no payload. Bounded(i64 i64) carries two integers.

Construction

Build a value with EnumName.Variant(args). Nullary variants drop the parentheses:

let good = Result.Ok(42)
let bad  = Result.Err("oops")
let e    = Range.Empty
let b    = Range.Bounded(3 10)

Pattern Matching

Use when to match a value against its variants. Each arm binds the variant’s payload to fresh names; use _ to ignore a payload slot:

unwrap is {
  r Result -> ret i64 {
    when r {
      Ok(n)  -> { ret n }
      Err(_) -> { ret 0 - 1 }
    }
  }
}

Multi-field payloads bind each slot in order:

width is {
  r Range -> ret i64 {
    when r {
      Empty          -> { ret 0 }
      Bounded(lo hi) -> { ret hi - lo }
    }
  }
}

A nullary variant matches by bare name (Empty -> { ... }).

Exhaustiveness

A when over an enum must cover every variant. If you leave one out and provide no wildcard arm, the compiler rejects the program:

Shape is enum {
  Circle(i64)
  Square(i64)
  Triangle(i64 i64 i64)
}

area_kind is {
  s Shape -> ret i64 {
    when s {
      Circle(_) -> { ret 1 }
      Square(_) -> { ret 2 }
      -- ERROR: missing `Triangle` arm (no wildcard)
    }
  }
}

Add a _ catch-all to make the match exhaustive without listing every variant:

kind_of is {
  s Shape -> ret i64 {
    when s {
      Circle(_) -> { ret 1 }
      Square(_) -> { ret 2 }
      _         -> { ret 99 }
    }
  }
}

Generic Enums

Enums can take type parameters in square brackets (see the Generics chapter for the full picture). The two most important generic enums ship in the standard library:

Option[T] is enum {
  Some(T)
  None
}

Result[T E] is enum {
  Ok(T)
  Err(E)
}

A generic machine can match on them just like a concrete enum:

unwrap_or[T] is {
  o Option[T] d T -> ret T {
    when o {
      Some(v) -> { ret v }
      None    -> { ret d }
    }
  }
}

When you construct a None (or any variant whose payload doesn’t pin down the type parameters), annotate the binding so the compiler can pick the concrete instantiation:

main is {
  _ -> {
    let x = Option.Some(42)        -- T = i64 inferred from 42
    let y Option[i64] = Option.None -- annotation needed: payload-free
    let a = unwrap_or(x 0)
    let b = unwrap_or(y 99)
  }
}

Option[T] and Result[T E] are also available — with helpers like is_some, is_none, is_ok, is_err, and unwrap_or — from std.option and std.result. See the Standard Library chapter.