7. Optionals, unions, and match
Model absence with T? and none, alternatives with unions, and consume both with match.
After this lesson you can
- Declare optional fields and default them with ?? - Construct union variants and dispatch bare records by shape - Destructure values with match, ending in a _ or binding arm
Before you start: The @document and gathering
A T? field accepts a value or the literal none; the ?? operator supplies the default (bob.bio ?? "anonymous"), evaluating its right side only when needed. Use T? when the only states are present and absent — when absence carries information, reach for a union.
A union names its variants: construct one as Status::Failed { reason: "timeout" }, or — where the expected type is already a union — write a bare record and let the field shape pick the variant. match takes the value apart; record payloads destructure as Status::Failed { reason } => ..., and the arm list must end with a _ wildcard or a binding arm so every case is covered.
§ 1Exercise: Absence and alternatives
Model a status union and an optional bio; extract the failure reason with match and default the bio with ??.
union Status {
Ok { code: u32 }
Failed { reason: utf8 }
}
let bob = { name: "Bob", bio: none }
@document
type Doc {
status: Status
label: utf8
display: utf8
}
status = Status::Failed { reason: "timeout" }
label = match status {
Status::Failed { reason } => reason,
_ => "ok",
}
display = bob.bio ?? "anonymous"
Expected result
wcl eval doc.wcl label prints "timeout" and wcl eval doc.wcl display prints "anonymous".
Hint
Drop the _ arm and the parser refuses the match outright: every match must end with a wildcard or binding arm.