Pattern matching
Tolk supports a match expression for pattern matching. It works both on types and on expressions.
match for union types
Pattern matching on union types is used in message handling.
type IncomingMessage =
| CounterIncBy
| CounterReset
// ...
// ... after parsing a message
match (msg) {
CounterIncBy => {
newCounter = curCounter + msg.byValue
}
CounterReset => {
newCounter = 0
}
// ...
}This is a general mechanism compatible with any union type:
fun processValue(value: int | slice) {
match (value) {
int => {
value * 2
}
slice => {
value.loadUint(8)
}
}
}A match on a union must be exhaustive: all alternatives must be covered.
fun errDemo(v: int | slice | Point) {
match (v) {
slice => { v.loadAddress() }
int => { v * 2 }
// error: missing `Point`
}
}else is not allowed for unions, but is permitted for a lazy match.
Syntax details
-
After
=>, one of the following is allowed:- a block:
A => { ... }; - an expression:
A => 123; - a return statement:
A => return SOME_EXPR; - a throw statement:
A => throw ERR_CODE.
- a block:
-
A comma is:
- optional after a block:
A => { ... } B => { ... }; - required in all other cases:
A => 1, B => 2.
- optional after a block:
-
A
matchcan be used as an expression:return match (v) { ... }. -
Variable declarations are allowed inside:
match (val v = ...).
match as expression
match can be used in expression position. In this form, it can be:
- assigned to a variable:
var smth = match (v) { ... }; - returned from a function:
return match (v) { ... }.
type Pair2 = (int, int)
type Pair3 = (int, int, int)
fun getLast(tensor: Pair2 | Pair3) {
return match (tensor) {
Pair2 => tensor.1,
Pair3 => tensor.2,
}
}Variables declaration
A variable may be declared directly in the match expression.
fun getPair2Or3(): Pair2 | Pair3 {
// ...
}
fun demo() {
match (val v = getPair2Or3()) {
Pair2 => return v.0 + v.1,
Pair3 => throw v.0 + v.1 + v.2,
}
}match for expressions
match can be used with constant expressions, similar to switch:
val nextValue = match (curValue) {
1 => 0,
0 => 1,
else => -1
};Rules:
- Only constant expressions are allowed before
=>. elseis required whenmatchis used as an expression.elseis optional whenmatchis used as a statement.
// statement form
match (curValue) {
1 => { nextValue = 0 }
0 => { nextValue = 1 }
-1 => throw NEGATIVE_NOT_ALLOWED
}
// expression form, `else` required
val nextValue = match (curValue) {
// ...
else => 1 + 2
}All comparable types are supported, including addresses and enums.
match for enums
Pattern matching on enums requires exhaustive coverage of all cases:
match (someColor) {
Color.Red => {}
Color.Green => {}
// error: Color.Blue is missing
}Alternatively, use else to handle the remaining values:
match (someColor) {
Color.Red => {}
else => {}
}Last updated on