Pattern Matching

match compares a value against a list of patterns and runs the first case that fits. Patterns can check a value, its type, which enum case it is, or its shape, and take the pieces they need out of it in the same step. This page covers every kind of pattern, and the same patterns used for destructuring outside a match. See Match for the grammar.

Match

match takes a value and a block of cases. Each case is a pattern, an optional if guard, then, and a branch - one expression or a block, as in if. Cases are tried from the top, and only the first that matches runs. _ matches anything, so a final case _ handles everything the others didn't.

As a value

Where a value is wanted - after :=, after return, as an argument - a match gives the value of the first case that matches. Each case's branch is then a value: one expression, or a block whose last expression gives it. When no case matches, the value is undefined, so the match's type is its cases' types joined, with Undefined added unless every value is taken: by a case _ or a name, or by a case for each of an enum's cases.

Literals and names

A number, a string, true or false matches a value equal to it, and a minus sign can go in front of a number. A case true and a case false together take every Boolean. A name starting with a lowercase letter matches anything and binds the value to that name for the case's branch, as other does above. A name starting with an uppercase letter is never a new binding: it's a type, as described below. The case of the first letter is how a pattern tells the two apart.

Guards

if after a pattern adds a condition, checked only once the pattern has matched. It can use the names the pattern bound. When the guard fails, the next case is tried, just as if the pattern hadn't matched.

A guarded match can stand in for an if/else if/else chain: each condition becomes a guard, in order, and case _ is the final else - with the difference that its cases can test patterns as well as conditions.

Types

A type's name matches a value of that type. as name binds the value, now known to be that type, so the branch can use what the type has - the usual way to take a union or an Unknown apart. An interface's name matches any value whose type implements it.

Enum cases

An enum case is matched by its full name, Enum.Case. A case carrying values in order takes a pattern for each in parentheses, and one with named fields takes them in braces. Each of those inner patterns can itself be any pattern, so Shape.Circle(0.0) matches only a circle of radius zero. The same case can appear several times with different guards, as Shape.Box does.

Structs

Type{field, ...} matches an instance of that struct and binds the named fields. field as pattern matches the field against another pattern instead of binding it, so x as 0.0 requires x to be zero. Fields that aren't listed can be anything. Without the type's name in front, {name} matches any struct that has a name field.

Tuples

(a, b) matches a tuple with exactly that many elements, each against its own pattern. Matching on a tuple built for the purpose - an ordering and a flag above - is how a match checks several values at once - the flag here could as well be matched with true or false in its place.

Nesting and binding the whole

Patterns nest to any depth: a field can be matched by a struct pattern, a tuple element by an enum case, and so on. as name after a struct, tuple or enum-case pattern binds the whole matched value as well as its parts.

Errors

A value that might be an error is matched with Error patterns: Error, Error(e) for the error itself, and with value for the value attached to it. Every other pattern matches only a successful value, so the last case above gets the result. A specific kind of error is matched by its type, like case ParseError then. See Errors.

Destructuring

let, function parameters and lambda parameters take a simpler kind of pattern that always matches: a name, {field, other as renamed} for a struct, (a, b) for a tuple, and [first, ...rest] for a list. All three allow x as y on an element and one ...rest anywhere. They take a value apart whose shape is already known - to handle several possible shapes, use match. See Argument Destructuring.