Pattern Matching
match handles explicit cases and the compiler checks exhaustiveness.
Variants
Match every union or enum variant by name, binding payloads where a case carries data.
union Download:
Queued
Running(Int)
Done(String)
Failed(String)
pure func describe(download: Download) -> String:
match download:
Queued: "queued"
Running(percent): "running " + percent.to_string() + "%"
Done(path): "saved to " + path
Failed(message): "failed: " + message
-- describe(Queued) == "queued"
-- describe(Running(40)) == "running 40%"
-- describe(Done("build/app")) == "saved to build/app"
-- describe(Failed("timeout")) == "failed: timeout"
Literals
Match literal strings, numbers, and booleans directly. Use a named fallback when you still need the unmatched value.
pure func command_label(command: String) -> String:
match command:
"add": "add item"
"list": "list items"
"quit": "exit"
other: "unknown command: " + other
pure func status_label(code: Int) -> String:
match code:
200: "ok"
201: "created"
400: "bad request"
404: "not found"
500: "server error"
other: "http " + other.to_string()
pure func confirmed_label(confirmed: Bool) -> String:
match confirmed:
True: "confirmed"
False: "not confirmed"
-- command_label("add") == "add item"
-- command_label("sync") == "unknown command: sync"
-- status_label(400) == "bad request"
-- status_label(418) == "http 418"
-- confirmed_label(False) == "not confirmed"
Tuples
Tuple patterns can match the shape of each position at the same time.
pure func summarize(result: (Result[Int, String], Option[String])) -> String:
match result:
(Ok(total), None):
"ready: " + total.to_string()
(Ok(total), Some(warning)):
"ready: " + total.to_string() + " (" + warning + ")"
(Err(message), None):
"blocked: " + message
(Err(message), Some(warning)):
"blocked: " + message + " (" + warning + ")"
-- summarize((Ok(12), None)) == "ready: 12"
-- summarize((Ok(12), Some("cached"))) == "ready: 12 (cached)"
-- summarize((Err("bad input"), None)) == "blocked: bad input"
-- summarize((Err("bad input"), Some("retry"))) == "blocked: bad input (retry)"
List Patterns
List patterns include exact shapes, such as [] and [cmd, item], plus spread tails such as [command, ...rest].
pure func route(args: List[String]) -> String:
match args:
[]: "missing command"
["list"]: "list"
["add", item]: "add " + item
["remove", item]: "remove " + item
["move", from, to]: "move " + from + " to " + to
[command, ...rest]:
"unknown " + command + " with " + rest
.length()
.to_string() + " args"
-- route([]) == "missing command"
-- route(["list"]) == "list"
-- route(["add", "milk"]) == "add milk"
-- route(["move", "todo", "done"]) == "move todo to done"
-- route(["archive", "old", "now"]) == "unknown archive with 2 args"
Nested Patterns
Patterns compose, so tuples, Option, Result, literals, and variants can be matched in one expression.
pure func describe_lookup(result: Result[Option[Int], String]) -> String:
match result:
Ok(Some(score)):
"score: " + score.to_string()
Ok(None):
"missing score"
Err(message):
"error: " + message
pure func describe_pair(pair: (Option[Int], Option[Int])) -> String:
match pair:
(Some(left), Some(right)):
"both: " + (left + right).to_string()
(Some(left), None):
"left only: " + left.to_string()
(None, Some(right)):
"right only: " + right.to_string()
(None, None):
"neither"
-- describe_lookup(Ok(Some(91))) == "score: 91"
-- describe_lookup(Ok(None)) == "missing score"
-- describe_lookup(Err("bad row")) == "error: bad row"
-- describe_pair((Some(1), Some(2))) == "both: 3"
-- describe_pair((None, None)) == "neither"
Catch-all
_ matches a value without binding it. Use it when every remaining case really has the same behavior.
pure func access_level(role: String) -> String:
match role:
"admin": "full"
"editor": "write"
_: "read-only"
-- access_level("admin") == "full"
-- access_level("viewer") == "read-only"
Exhaustiveness
A match must cover every possible input shape.
enum TrafficLight:
Red
Yellow
Green
pure func next_action(light: TrafficLight) -> String:
match light:
Red: "stop"
Yellow: "slow"
Green: "go"
-- next_action(Red) == "stop"
-- next_action(Yellow) == "slow"
-- next_action(Green) == "go"
Example
pure func route(args: List[String]) -> String:
match args:
["add", item]: "add " + item
["list"]: "list"
[cmd, ...rest]:
"unknown command: " + cmd + " with " + rest.length().to_string() + " args"
[]: "missing command"
func main(args: List[String]) -> Void:
print(route(["add", "milk"])) -- prints: add milk
print(route(["archive", "old", "now"])) -- prints: unknown command: archive with 2 args
Try it
blorp run commands.brp