Skip to content

Control Flow

Jiang separates control-flow statements from expressions that produce values. Blocks, if, and switch can produce values; return, throw, break, and continue do not continue normally.

Int value = {
Int base = 40;
base + 2
}

A block’s value comes from its final tail expression. Without a tail expression, the block value is ().

An if condition is followed directly by a block. As a statement, else may be omitted:

if value < 0 {
print("negative");
}

As an expression, if must include else and both branches must produce compatible values:

Int sign = if value < 0 {
-1
} else {
1
}

Statement-style branches can still include else:

if value < 0 {
print("negative");
} else {
print("non-negative");
}

switch matches patterns and can produce a value:

enum Mode {
read,
write,
}
Mode mode = Mode.read;
Int code = switch mode {
.read => 1,
.write => 2,
}

Branches may use a block:

Int code = switch mode {
.read => {
print("read");
1
},
.write => 2,
}
Int! count = 0;
while count < 5 {
count = count + 1;
}

break exits the current loop and continue starts the next iteration:

while count < 10 {
count = count + 1;
if count == 3 {
continue;
} else {
print(count);
}
if count == 8 {
break;
}
}

for pattern in expr iterates arrays, slices, and other iterable values:

Int[_] values = [10, 20, 30];
for item in values {
print(item);
}

Tuple destructuring is a separate statement inside the loop:

(Int, Int)[_] pairs = [(1, 2), (3, 4)];
for pair in pairs {
(_ left, _ right) = pair;
print(left + right);
}

Ranges use start..end:

for i in 0..10 {
print(i);
}

guard is used for early exit while carrying successful bindings into the following scope:

() print_value(Int? maybe) {
guard maybe is some value else {
return ();
}
print(value);
return ();
}

The else block must be non-empty and end in return, break, continue, or throw.

defer runs when the current block exits:

defer handle$.free();
defer {
log("closing");
handle$.free();
}

Use defer expr; for a single operation or defer { ... } for several operations.

try expr catch (...) => fallback handles a T@E result:

Int value = try parse(text) catch (err) => {
log_error(err);
0
}

Use catch () when the error value is not needed:

Int value = try parse(text) catch () => 0;