How do I use a guard in a for-in loop, including the expression form?
← Control Flow · Ref: Q1357
A for-in loop ('for item in collection') accepts a guard in its header, written BEFORE the loop variable and separated by 'with' (or 'then'). The for-in loop also has an expression form yielding a value via a returning variable.
FOR-IN EXPRESSION WITH A ?= GUARD
prefix as String? joined <- for prefix ?= getPrefix() with item in items <- rtn as String: "" rtn: `${rtn}${prefix}${item}`
The guarded assignment (?=) assigns getPrefix() to 'prefix' and checks it is SET. If unset, the loop body is skipped and 'joined' is the initial "". (Note: build strings with interpolation `${...}`, not 3+ chained '+', which EK9 rejects with E11068.)
FOR-IN STATEMENT WITH A :=? GUARD
marker as String? count <- 0 for marker :=? getPrefix() with item in items if marker? count: count + 1
GUARD vs LOOP VARIABLE
The guard variable ('prefix', 'marker') is separate from the loop variable ('item'). Order is 'for <guard> with <var> in <collection>'; the guard cannot go after the collection.
See Q65 for the plain for-in. See Q1356 for for-range guards. See Q1361 for guards across all expression-form constructs. See Q76 for guards in for loops overview.
Example
defines module qa.controlflow.guardforinexpression defines program GuardForInExpressionDemo() stdout <- Stdout() items <- ["alpha", "beta", "gamma"] // for-in EXPRESSION with a ?= guard (guard FIRST, then 'with item in collection') prefix as String? joined <- for prefix ?= getPrefix() with item in items <- rtn as String: "" rtn: `${rtn}${prefix}${item}` stdout.println(`joined: ${joined}`) // for-in STATEMENT with a :=? guard marker as String? count <- 0 for marker :=? getPrefix() with item in items if marker? count: count + 1 stdout.println(`count is ${count}`) defines function getPrefix() <- rtn as String: "> "
Common mistakes
E02001 — The guard is the pre-flow and must come BEFORE the loop variable: 'for <guard> with <var> in <collection>'. See ek9 -h E02001.
Incorrect:
joined <- for item in items with prefix ?= getPrefix() <- rtn as String: "" rtn: `${rtn}${prefix}${item}`
Correct:
joined <- for prefix ?= getPrefix() with item in items <- rtn as String: "" rtn: `${rtn}${prefix}${item}`
Other ways to ask this
- Can a for item in collection loop use a guard variable?
- for-in as an expression with a ?= guard
- guarded assignment when iterating a collection
- How do I guard a for-each loop that returns a value?
Coming from another language?
Java: enhanced-for is a statement; it cannot bind a guarded, isSet-checked header variable nor produce a value. Kotlin/Swift: for-each is a statement; value production needs map/fold. EK9: for-in takes a guard (<-, ?=, :=?) before the loop variable, and its expression form yields the returning variable, with the guard able to skip iteration entirely when unset.
Keywords: returning, with, isset, guarded, iterate, :=?, collection, for-each, for-in, for, expression, ?=, guard