How do I use a guard in a for-range loop, including the expression form?
← Control Flow · Ref: Q1356
A for-range loop ('for i in start ... end') accepts a guard in its header, written BEFORE the loop variable and separated by 'with' (or 'then'). The for loop also has an expression form that yields a value via a returning variable.
FOR-RANGE EXPRESSION WITH A ?= GUARD
The guard comes first, then 'with', then the loop variable and range:
step as Integer? total <- for step ?= getStep() with i in 1 ... 5 <- rtn as Integer: 0 rtn: rtn + (i * step)
If getStep() is unset the guarded assignment leaves 'step' unset, the loop body is skipped, and 'total' is the initial value 0.
FOR-RANGE STATEMENT WITH A :=? GUARD
factor as Integer? sum <- 0 for factor :=? getStep() with i in 1 ... 3 sum: sum + (i * factor)
HEADER ORDER
The grammar is 'for <guard> with <var> in <range>'. The guard variable ('step', 'factor') is SEPARATE from the loop variable ('i'). Putting the guard after the range ('for i in 1 ... 5 with step ?= ...') is NOT valid.
BY STEP
A for-range may add 'by <step>' for non-unit or descending ranges; the guard still comes first: 'for g <- getG() with i in 10 ... 1 by -1'.
See Q64 for the plain for-range. See Q1149 for 'by'. See Q1357 for for-in guards. See Q1361 for guards across all expression-form constructs.
Example
defines module qa.controlflow.guardforrangeexpression defines function getStep() <- rtn as Integer: 2 defines program GuardForRangeExpressionDemo() stdout <- Stdout() // for-range EXPRESSION with a ?= guard (guard FIRST, then 'with i in range') step as Integer? total <- for step ?= getStep() with i in 1 ... 5 <- rtn as Integer: 0 rtn: rtn + (i * step) stdout.println(`weighted total is ${total}`) // for-range STATEMENT with a :=? guard factor as Integer? sum <- 0 for factor :=? getStep() with i in 1 ... 3 sum: sum + (i * factor) stdout.println(`sum is ${sum}`)
Common mistakes
E02001 — The guard is the pre-flow and must come BEFORE the loop variable: 'for <guard> with <var> in <range>'. The guard variable is separate from the loop variable. See ek9 -h E02001.
Incorrect:
total <- for i in 1 ... 5 with step ?= getStep() <- rtn as Integer: 0 rtn: rtn + (i * step)
Correct:
total <- for step ?= getStep() with i in 1 ... 5 <- rtn as Integer: 0 rtn: rtn + (i * step)
Other ways to ask this
- Can a for i in 1 ... n loop use a guard variable?
- for-range as an expression with a ?= guard
- guarded assignment in a numeric for loop
- How do I put a guard before the range in a for loop?
Coming from another language?
Java: a for loop is a statement and cannot bind a guarded, isSet-checked variable in its header nor yield a value. You would compute a nullable outside the loop and check it manually. Python/Kotlin: for-comprehensions/folds produce values but have no isSet-guard concept. EK9: the for-range header takes a guard (<-, ?=, :=?) before the loop variable, and its expression form yields the returning variable — with the guard able to skip the whole loop when unset.
Keywords: returning, with, isset, for-range, range, guarded, :=?, for, expression, loop, ?=, by, guard