Match
match runs the branch whose pattern fits a value. Each branch starts with
when, lists one or more patterns separated by commas, and ends at the next
when, else, or end:
func area(Shape shape) f64 do
match shape do
when CIRCLE(radius) then
return 3.14159 * radius * radius
when RECT(width, height) then
return width * height
when EMPTY then
return 0.0
end
endOn an enum, patterns are member names. They may be written plainly (CIRCLE)
or with their enum (Shape.CIRCLE). A member pattern can give a pattern for
each value the member carries, in order, or for some of them by the names the
member gives them (RECT(height: h)). A name binds the value, which is then
a variable in that branch; _ skips a value, and leaving out the
parentheses skips them all. Any other pattern fits only some values, as in
ERROR(EMPTY) or SOME(0):
func message(Result[int, ParseError] result) str do
match result do
when OK(0) then
return "zero"
when OK(n) then
return f"the number {n}"
when ERROR(EMPTY) then
return "nothing to read"
when ERROR(BAD_DIGIT(c)) then
return f"'{c}' is not a digit"
end
endA when with several patterns cannot bind names. A match on an enum must
handle every member, unless it has an else; a branch handles a member when
its patterns for the member's values fit every value and it has no
guard. The compiler lists any member that is missing. A function
whose last statement is such a match, with a return at the end of every
branch, always returns.
Integers, characters, strings, and booleans match by value. Patterns are literals, negative numbers, constants, and, for integers and characters, ranges that hold both of their ends:
match command do
when "start", "go" then
print("starting")
when "stop" then
print("stopping")
else
print("unknown command")
end
match c do
when 'a' to 'z', 'A' to 'Z' then
print("letter")
when '0' to '9' then
print("digit")
endA match on these types runs no branch when nothing fits and there is no
else. A value may appear in only one pattern, and no value in two ranges
written with literals. Floats cannot be matched, since comparing floats for
equality is rarely meaningful; bind a name to the value and compare it in a
guard.
A name at the top of a match on any of these types, on a struct, or on a
tuple binds the value, unless it is a constant: it fits every value, as _
does, and makes the match handle every value, as an else does. The name of
a variable is an error there, since a new variable would hide it; compare
with it in a guard, as in when n if n == limit.
A struct is matched with its name and patterns for its fields, in order or
some of them by name. null fits a struct that is null, which no other
struct pattern does:
func place(Point p) str do
match p do
when null then
return "nowhere"
when Point(0, 0) then
return "origin"
when Point(x: 0) then
return "on the y axis"
when Point(x, y) then
return f"at {x}, {y}"
end
endSuch a match handles every value when it has null and a struct pattern
whose patterns fit every value, or a name.
A tuple is matched with a pattern for each item, in parentheses. An item's pattern can be any pattern, a name binding the item's value:
func describe((int, int) point) str do
match point do
when (0, 0) then
return "origin"
when (0, y) then
return f"on the y axis at {y}"
when (x, y) then
return f"at {x}, {y}"
end
end
match (command, count) do
when ("add", 1) then
print("one more")
when (Option.SOME(n), _) then
print(n)
endInside another pattern, a name is a constant or an enum member when one has
it, and otherwise a new variable. Branches are tried in order; a branch whose
pattern fits every value, such as (x, y), makes the match handle every
value, as an else does. Several patterns in one when cannot bind names.
To match several values at once, match a tuple of them, as in
match (command, count) do.
Guards
if after the patterns of a when adds a guard: the branch runs only when a
pattern fits and the guard is true, and otherwise the branches after it are
tried. The guard sees the names the patterns bind:
match score do
when n if n > 100 then
print("too high")
when 90 to 100 then
print("A")
when n then
print(f"{n} points")
endA branch with a guard handles no values for the rest of the match: a member it names is still missing, and the values it names may appear again.
break and continue inside a match apply to the loop around it.