Overview
when is a loop with a built-in answer to one question: did the loop finish
its work, or was it cut short? A plain while loop cannot tell you — you have
to thread a boolean flag through the body yourself. when folds that flag into
the language and routes control to one of two completion blocks.
Shape
when (condition) {
// body — runs while `condition` is true, exactly like `while`
} then {
// runs once, if the loop exited cleanly
} end {
// runs once, if the loop was cut short
}
Both then and end are optional. The body behaves identically to a while
loop: the condition is re-evaluated before every iteration, the body is a fresh
scope each pass, and break / continue work as they do in any loop.
The completion decision
After the loop stops, exactly one of then or end is eligible to run:
| How the loop stopped | Block that runs |
|---|---|
| condition went false after ≥ 1 full iteration | then |
| condition was false from the start (0 iterations) | end |
a break fired |
end |
Read it as two flags — completed (a body iteration reached the back-edge) and
broke (a break fired):
then ⇐ completed && !broke
end ⇐ broke || !completed
then is the "happy path" — the loop did its job and ran out of work. end is
the "short-circuit path" — either nothing happened, or someone bailed out early.
A worked example
func:failsafe = int32(tbb32:err) {
exit 1;
};
func:main = int32() {
int32:i = 0i32;
int32:sum = 0i32;
when (i < 5i32) {
sum = sum + i;
i = i + 1i32;
} then {
sum = sum + 100i32; // clean exit -> add the bonus
} end {
sum = sum + 1i32; // unreachable here: the loop always completes
}
exit sum; // (0+1+2+3+4) + 100 = 110
};
The loop sums 0..4, the condition goes false after the fifth check, and —
because at least one iteration completed and no break fired — then runs.
Where to go next
- The exact rules behind the table, including the subtle zero-iteration case, are in then and end semantics.
- If you came here from
while, the when vs while chapter shows the flag-threading patternwhenreplaces.