Skip to main content
Tolk provides constructs for controlling contract flow.
  • Use if, assert, and loops for conditional logic.
  • Use match expression 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 boolean or an integer. If not equals 0, then true:
if (someInt) {     // means "someInt != 0"
    // ...
}
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
}
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.