Conditions and loops
Tolk provides constructs for controlling contract flow.
- Use
if,assert, and loops for conditional logic. - Use
matchexpression for pattern matching.
if statement
if statement works as in most languages. else if and else blocks are optional.
if (condition) {
// ...
} else {
// ...
}A condition must be a bool. Integers are not implicitly converted — write the comparison explicitly:
if (someInt != 0) {
// ...
}The same rule applies to while, do while, ternary, assert, and the unary ! operator. There is no gas overhead — the compiler strips the != 0 comparison off whenever it would translate to a redundant TVM instruction.
The body of if and else must be enclosed in { ... }:
// invalid
if (condition)
someFn();
// valid
if (condition) {
someFn();
}assert statement
assert throws an exceptions if a condition is false.
assert (condition) throw ERR_CODE;It is equivalent to the following form:
if (!condition) {
throw ERR_CODE;
}match expression
match is used to perform different actions for different values of a variable. A common use case is routing values of a union type:
fun demo(v: A | B | C) {
match (v) {
A => {
// use `v.aField` etc.
}
B => { /* ... */ }
C => { /* ... */ }
}
}The match is equivalent to a series of if-else checks:
fun demo(v: A | B | C) {
if (v is A) {
// use `v.aField` etc.
}
else if (v is B) { /* ... */ }
else { /* ... */ }
}The match can also be used for expressions, switch-like behavior:
fun invertNumber(curValue: int) {
return match (curValue) {
1 => 0,
0 => 1,
else => throw ERR_UNEXPECTED,
};
}Ternary operator
The ternary form condition ? when_true : when_false is available:
fun myAbs(v: int) {
return v < 0 ? -v : v
}If the types of when_true and when_false differ, the result becomes a union type. In most cases this is unintended, so the compiler reports an error.
fun demo(a: int32, b: int64) {
// instead of inferring result1 as `int32 | int64`,
// an error "probably it's not what you expected"
val result1 = a > b ? a : b;
// correct: specify the type manually
val result2: int = a > b ? a : b;
// also correct, types are compatible
val result3 = a > b ? a as int64 : b;
}while loops
while and do-while loops repeatedly execute their bodies while the condition remains true. while checks the condition first and may not execute the body at all, whereas do-while runs the body first.
fun demoWhile(i: int) {
while (i > 0) {
debug.print(i);
i -= 1;
}
}
fun demoDoWhile() {
var rand: int;
do {
rand = random.uint256();
} while (rand % 2 == 0);
return rand; // an odd number
}Variables declared inside the body of do while are not visible in its condition. Declare them before the loop:
var found: bool;
do {
found = ...
} while (found);while is used to iterate over maps:
fun iterateOverMap(m: map<int32, Point>) {
var r = m.findFirst();
while (r.isFound) {
// ...
r = m.iterateNext(r);
}
}repeat loop
The repeat (N) statement executes its block N times:
repeat (5) {
// executed 5 times
}N may be either a constant or a variable.
break and continue
The keywords break and continue are not supported.
Last updated on