Choices, when, and ?
Choices
A choice is a tagged union: a value is exactly one of its variants, and a
variant may carry a payload.
choice Shape {
Circle(real64),
Rectangle,
}
s: Shape = Circle(2.0);
when expressions
when matches a value against patterns and produces a result. It has two forms:
a literal/wildcard form and a variant-binding form.
// literal / wildcard
label = when value {
is 1 { "one" }
is _ { "many" }
};
// bind a variant payload
area = when s {
Circle(radius) => 3.14159 * radius * radius;
Rectangle => 0.0;
};
Exhaustiveness and unreachable arms
The type checker proves that every choice variant is handled. A match may
list every variant explicitly or finish with _. If variants are missing, the
diagnostic names each one in declaration order. Repeating a variant, or placing
an arm after _, is an error because that arm can never be selected.
import fmt;
choice Status { Ready, Running(int), Failed(text) }
label = when status {
Ready => "ready";
Running(count) => fmt.format("running {}", count);
Failed(message) => message;
};
Literal matches over int, real numbers, glyph, and text require a final
_ because their possible values are not finite. Duplicate literal arms are
rejected. A bool match is exhaustive when it handles both true and false,
so it does not need a redundant fallback:
state = when enabled {
true => "enabled";
false => "disabled";
};
Optional and result: maybe and outcome
The standard library builds two common choices on top of this machinery:
maybe—Maybe<T>withpresent(value),absent(default), andvalue_or().outcome—Outcome<T, E>withdone,failed, andfailure_or().
The ? operator
The postfix ? operator propagates the "empty" or "error" case of a Maybe or
Outcome out of the enclosing function, returning early, and otherwise unwraps
the contained value. It binds tighter than binary operators.
import outcome;
fn total(): outcome.Outcome<int, text> {
a = read_number()?; // returns early on failure
b = read_number()?;
return outcome.done(a + b, "");
}
Printing choices
Choices print by default — no boilerplate. io.println(value) and
fmt.format("{}", value) render a choice as its variant name, plus the payload
in parentheses when the variant carries one:
import io;
choice Shape { Circle(int), Named(text), Empty }
a: Shape = Circle(5);
io.println(a); // Circle(5)
io.println(Empty); // Empty
This works when every variant payload is a scalar or text (including generic
choices instantiated with such types, like Maybe<int>). A choice whose variant
carries a record, array, or tuple is not printable by default — give the payload
type its own to_text rendering or format the fields explicitly. See
Display.