How do guard variables work in while loops?
← Control Flow · Ref: Q77
In EK9, guard variables in while loops combine variable creation with an isSet check. Unlike for loop guards that evaluate once, while loop guards are re-evaluated on EVERY iteration.
BASIC WHILE GUARD
Use the declaration operator (<-) with 'with' to link the guard to the loop condition:
while value <- getNextItem() with value > 0 process(value)
Both checks happen each iteration: first the guard (isSet), then the condition (> 0). If either fails, the loop terminates.
GUARD RE-EVALUATION
This is the key difference from for loop guards. In a while loop, the guard expression is called again each time the loop condition is checked. This makes while guards perfect for consuming iterators or polling:
while item <- source.next() with item? process(item)
GUARD TERMINATES LOOP
If the guard becomes unset on any iteration, the loop terminates cleanly. No exception is thrown. This is a safe alternative to checking for null in a while condition.
WHILE EXPRESSION WITH GUARD
While loops can be expressions that return a value:
result <- while value <- getNext() with value > 0 <- rtn as String: "none found" rtn: $value
If the guard is unset on the first check, the expression evaluates to the default return value.
THREE GUARD OPERATORS IN WHILE
All three guard operators work in while loops:
1. Declaration (<-): Creates variable, checks isSet each iteration while value <- getNext() with condition 2. Assignment (:=): Assigns each iteration, NO isSet check while existing := getNext() with existing > 0 3. Guarded assignment (?=): Assigns only if RHS is SET while existing ?= getNext() with condition
See Q66 for basic while loops. See Q67 for do-while loops. See Q74 for guards in if. See Q76 for guards in for loops (one-time evaluation).
Example
defines module qa.flow.guard.whileloop defines function supplyCounter() <- rtn <- Integer() rtn: 5 supplyStart() as pure -> initial as Integer <- rtn as Integer: initial defines program GuardWhileDemo() stdout <- Stdout() // === BASIC WHILE GUARD === counter <- supplyStart(3) while guardedCount <- supplyCounter() with counter > 0 stdout.println(`Counter: ${counter} value: ${guardedCount}`) counter: counter - 1 // === ASSIGNMENT GUARD (no isSet check) === loops <- supplyStart(2) existing <- Integer() while existing := supplyCounter() with loops > 0 stdout.println("Assigned value: " + $existing) loops: loops - 1 stdout.println("While guard demo complete")
Common mistakes
E07390 — EK9 has no break statement. While loop guards combine declaration, isSet checking, and the loop condition, eliminating the need for break-based exit patterns. See ek9 -h E07390 for details.
Incorrect:
while true guardedCount <- supplyCounter() if not guardedCount? break if counter <= 0 break stdout.println(`Counter: ${$counter} value: ${$guardedCount}`) counter: counter - 1
Correct:
while guardedCount <- supplyCounter() with counter > 0 stdout.println(`Counter: ${counter} value: ${guardedCount}`) counter: counter - 1
Other ways to ask this
- Can I guard a while loop with a variable declaration?
- How does the while loop guard work in EK9?
- What is the difference between while guards and for guards?
Coming from another language?
Java: No guard in while. Must write: 'T v; while ((v = getNext()) != null && v > 0) { ... }' mixing assignment and null check in condition. Error-prone. Python: No guard in while. Walrus operator helps: 'while (v := get_next()) is not None and v > 0:' but only handles None. Rust: 'while let Some(v) = get_next()' for iterator consumption. Close to EK9 but limited to pattern matching. Go: No guard in while (Go only has for). Must use: 'for v := getNext(); v != nil; v = getNext() { ... }'. EK9: 'while value <- getNext() with value > 0' combines declaration, isSet check, and loop condition. Guard re-evaluates each iteration, perfect for consuming sequences.
Keywords: loop, guard, reevaluate, safe, flow, while, null-safe, isset, declaration, condition, consume, control, iteration, poll, terminate, branch