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.