Control flow decides which statements are evaluated, how branches are selected, and how loops are repeated or stopped.
Expr control-flow constructs are expressions. They can be used as statements, and several of them can also produce a value.
Expr supports these control-flow keywords:
The condition of `if`, `while`, `for`, and `loop` is written inside parentheses.
if(condition) { // body };
A control-flow construct normally ends with a semicolon when it is used as a statement.
A block is a list of statements inside braces.
{ a = 10; b = 20; a + b; };
A block evaluates its statements in order. The block result is the result of the last evaluated statement, unless execution is interrupted by `return`, `break`, or `continue`.
Blocks are commonly used as the body of `if`, `loop`, `while`, and `for`.
A single statement can be used without braces, but braces are recommended for scripts that may later be edited.
if(a > 0) sign = 'positive';
`if` evaluates a condition and runs a branch only when that condition is true.
if(value > 0) { print('positive'); };
The condition must be inside parentheses.
Use `else` to provide a branch for the false case.
if(value >= limit) { state = 'high'; } else { state = 'normal'; };
Without an `else` branch, an `if` whose condition is false produces `none()`.
result = if(false) { 123; }; result.is_none(); // true
Expr does not have a separate `elseif` keyword.
An `else if` chain is an `else` branch that contains another `if`.
probeError = 0.03; status = if(probeError <= 0.01) { 'excellent'; } else if(probeError <= 0.05) { 'acceptable'; } else if(probeError <= 0.10) { 'warning'; } else { 'failed'; };
The conditions are tested from top to bottom. The first true branch is evaluated, and the remaining branches are skipped.
`else` binds to the nearest unmatched `if`.
if(a) if(b) print('a and b'); else print('a and not b');
In this example, the `else` belongs to `if(b)`, not to `if(a)`.
Use braces when nested branches could be ambiguous.
Because `if` is an expression, it can be assigned to a variable.
message = if(toolLoaded) { 'Tool loaded'; } else { 'No tool'; };
This is useful for selecting one value from several branches.
When an `if` is used where a value is required, provide an `else` branch unless `none()` is an acceptable result.
feed = if(material == 'aluminum') { 900; } else { 600; };
`loop` repeats its body a fixed number of times.
count = 0; loop(5) { count += 1; };
The count expression is evaluated once before the loop starts.
repeats = 3; loop(repeats) { print('step'); };
The count is converted to an integer count. A zero or negative count runs zero iterations.
loop(0) { print('not printed'); };
`loop` is best when the number of repetitions is already known.
`while` repeats its body while its condition is true.
a = 1; while(a < 10) { a *= 2; };
The condition is evaluated before each iteration. If it is false before the first iteration, the body is not evaluated.
ready = false; while(ready) { print('not printed'); };
A `while` loop must change something that can eventually make the condition false. Expr has safety limits for excessive loop execution, but scripts should still be written so loops finish normally.
`for` is a loop with initialization, condition, and iteration expressions in the header.
for(initialization; condition; iteration) { // body };
The execution order is:
Example:
sum = 0; for(i = 0; i < 5; i += 1) { sum += i; };
After this script, `sum` is `10`.
Any `for` header expression can be omitted.
for(; i < 10; ) { i += 1; };
If the condition is omitted, the loop condition is treated as true.
for(;;) { break; };
Use `break` or another terminating condition when writing a loop without a condition.
`break` exits the nearest enclosing loop.
count = 0; while(true) { count += 1; if(count >= 3) { break; }; };
After this script, `count` is `3`.
`break` is valid only inside `loop`, `while`, or `for` bodies.
In nested loops, `break` exits only the innermost loop.
outer = 0; loop(3) { loop(3) { break; }; outer += 1; };
The inner `break` does not exit the outer `loop`.
`continue` skips the rest of the current loop body and moves to the next iteration of the nearest enclosing loop.
sum = 0; for(i = 0; i < 5; i += 1) { if(i == 2) { continue; }; sum += i; };
After this script, `sum` is `8` because `2` is skipped.
`continue` is valid only inside `loop`, `while`, or `for` bodies.
In a `for` loop, the iteration expression still runs after `continue`.
for(i = 0; i < 5; i += 1) { if(i < 3) { continue; }; print(i); };
The `i += 1` iteration expression still runs after each `continue`.
`return` stops the current evaluation scope and optionally provides a value.
function Clamp01(value) { if(value < 0) { return 0; }; if(value > 1) { return 1; }; return value; }
`return` can be written with or without a value.
return; return 123;
A `return` with a value returns that value. A `return` without a value returns no explicit value.
At top-level script evaluation, `return` stops evaluation of following statements.
a = 1; return a; a = 2; // not evaluated
Loops can produce a result. The result is normally the last value produced by the body.
last = loop(3) { value += 1; value; };
If a loop body is not evaluated, the loop result is `none()`.
result = loop(0) { 123; }; result.is_none(); // true
When a loop is used mainly for side effects, assign the values you need explicitly instead of relying on the loop result.
Control-flow conditions use Expr truthiness rules.
Common cases:
Examples:
if(0) { print('not printed'); }; if('text') { print('printed'); };
For type-specific rules, see Type system.
An `if` without an `else` can produce `none()`.
value = 10 + if(false) { 5; };
Use an `else` branch when the surrounding expression needs a number, string, or object.
value = 10 + if(false) { 5; } else { 0; };
This loop does not change `position`, so it cannot finish normally:
position = 0; while(position < 10) { print(position); };
Update the condition variable, use `break`, or choose `loop` when the number of repetitions is fixed.
Without braces, `else` binds to the nearest unmatched `if`.
if(a) if(b) print('both'); else print('which if?');
Use braces to make the intended branch explicit.
Previous: Expression rules
Next: Functions