Control Flow

Conditions require parentheses. There are no truthy values — conditions must be explicitly bool. Use != 0, != null, etc.

If / else

tape
if (x > 0) {
    io.println("positive");
} else if (x == 0) {
    io.println("zero");
} else {
    io.println("negative");
}

While loops

tape
var i: i64 = 0;
while (i < 10) {
    io.print_i64(i);
    i = i + 1;
}

For loops

Iterate over ranges:

tape
for (i in 0..10) {
    io.print_i64(i);
}

for (i in 0..=9) {
    io.print_i64(i);  // inclusive: 0 through 9
}

Iterate over slices or arrays:

tape
for (item in items) {
    process(item);
}

Iterate over an integer count:

tape
for (i in count) {
    io.print_i64(i);  // 0 to count-1
}

Iterator protocol

Any struct with a fn Type.next(*self) -> ?T method can be used with for:

tape
struct Counter { current: i64; end: i64; }

fn Counter.next(*self) -> ?i64 {
    if (self.current >= self.end) { return null; }
    let val = self.current;
    self.current = self.current + 1;
    return val;
}

var c = Counter { current: 0, end: 5 };
for (val in c) {
    io.print_i64(val);
}

Match

Tagged unions

Pattern matching on tagged unions uses Type.Variant syntax with field destructuring:

tape
match (shape) {
    Shape.Circle { radius } => { return 3.14 * radius * radius; }
    Shape.Rect { w; h } => { return w * h; }
    Shape.Point => { return 0.0; }
}

Bindings destructure the variant’s fields by name. Use .. to ignore remaining fields.

Enums

Match also works with enums — the scrutinee is compared directly against each variant:

tape
enum Direction : u8 { North = 0; East = 1; South = 2; West = 3; }

match (dir) {
    Direction.North => { move_forward(); }
    Direction.East => { turn_right(); }
    Direction.South => { turn_around(); }
    Direction.West => { turn_left(); }
}

Wildcard

Use _ as a catch-all arm for unmatched values:

tape
match (dir) {
    Direction.North => { move_forward(); }
    _ => { io.println("not going north"); }
}

Match must be exhaustive — either all variants are covered, or a _ wildcard is present.

Break and continue

tape
while (true) {
    let val = read_next();
    if (val == 0) { break; }
    if (val < 0) { continue; }
    process(val);
}

Return

tape
fn find(items: []i64, target: i64) -> ?i64 {
    for (i in 0..items.len) {
        if (items[i] == target) { return i; }
    }
    return null;
}

Last modified: