till
till(limit, step) counts up from 0, exposing the running value as $.
Where loop is "walk an index between two bounds", till is "count up
to a limit", and it desugars to loop(0, limit, step).
func:failsafe = int32(tbb32:err) {
exit 1;
};
func:main = int32() {
int32:total = 0i32;
till(5i32, 1i32) {
total += $; // $ takes 0, 1, 2, 3, 4
}
exit total; // 10
};
The $ value
Inside a till body, $ is the current running value, starting at 0 and
advancing by step until it reaches limit. The semantics match
loop(0i32, limit, step) exactly:
till(6i32, 2i32) {
// $ = 0, 2, 4
}
Desugaring
till(L, S) is defined as loop(0, L, S). Everything that is true of loop
holds for till: the exclusive upper bound, the zero-step failsafe, and
break / continue semantics. The K semantics encodes this directly —
till (L, S) B => loop (0, L, S) B — so both forms share one rule set.
When to use which
- Use
tillwhen you only care about the running value and always start at0. - Use
loopwhen you need a non-zerostartor want to emphasize that you are indexing a range.
Next: for-in.