Pattern matching
match expressions, if let, while let and let else — one pattern grammar across all four.
match is an expression. Its arms take an expression body or a block, and an arm can carry a guard.
@lang(try)
enum Option<T> {
SOME(T),
NONE,
}
function classify(value: Option<i32>): i32 {
return match (value) {
Option::SOME(x) if x > 0 -> x,
Option::SOME(_) -> 0,
Option::NONE -> -1,
};
}
Patterns match literals, tuples, enum variants with their payloads, atoms, and _ for the rest.
Alternatives are written with |.
function describe(state: atom): i32 {
return match (state) {
:ready -> 1,
:error -> -1,
_ -> 0,
};
}
if let
A let PATTERN = EXPR can stand where a condition goes, and it can be chained with ordinary
conditions.
@lang(try)
enum Option<T> {
SOME(T),
NONE,
}
function maybeValue(): Option<i32> {
return Option::SOME(42);
}
function read(): i32 {
if (let Option::SOME(v) = maybeValue()) {
return v;
}
return 0;
}
function readLarge(): i32 {
if (let Option::SOME(x) = maybeValue() && x > 10) {
return x;
}
return 0;
}
while let
The loop runs as long as the pattern keeps matching.
@lang(try)
enum Option<T> {
SOME(T),
NONE,
}
function nextValue(): Option<i32> {
return Option::NONE;
}
function total(): i32 {
let mut sum: i32 = 0;
while (let Option::SOME(v) = nextValue()) {
sum += v;
}
return sum;
}
let else
let else binds on the success path and hands the failure path to a block that must diverge —
return, break, continue, @panic, anything that does not fall through.
@lang(try)
enum Option<T> {
SOME(T),
NONE,
}
function maybeValue(): Option<i32> {
return Option::SOME(7);
}
function read(): i32 {
let Option::SOME(v) = maybeValue() else {
return -1;
};
return v;
}
The shorthand without a pattern is try-aware sugar: the value must be a @lang(try) enum, the name
binds the success payload, and the failure variant jumps to the else block. Using it on a value
that is not try-capable reports A0187.