Can while and do-while loops return values (loop expressions)?
← Control Flow · Ref: Q81
Yes. In EK9, both while and do-while loops can return values by declaring a return variable inside the loop body. The pattern is the same as for-range expressions.
WHILE EXPRESSION
Accumulate a sum using a while expression with a guard variable:
result <- while counter <- 0 with counter < limit <- rtn <- 0 rtn: rtn + counter counter: counter + 1
The outer '<- result' captures the loop result. 'counter <- 0' is a guard variable initialised to 0. 'with counter < limit' is the condition. The inner '<- rtn <- 0' declares the return variable. After the loop completes, the final value of 'rtn' is assigned to 'result'.
DO-WHILE EXPRESSION
The do-while expression form guarantees the body runs at least once:
result <- do counter <- 0 <- rtn <- 0 rtn: rtn + counter counter: counter + 1 while counter < limit
The body executes first, then 'counter < limit' is checked. The inner '<- rtn <- 0' declares the return variable.
WHILE VS DO-WHILE
while expression: Condition checked BEFORE each iteration. If condition is immediately false, the return variable keeps its initial value.
do-while expression: Body executes ONCE before condition check. Return variable always reflects at least one iteration.
SIMPLE WHILE EXPRESSION
Without a guard variable (using variables from outer scope):
n <- 1 sum <- while n <= 10 <- rtn <- 0 rtn: rtn + n n: n + 1
WHEN TO USE LOOP EXPRESSIONS
Use loop expressions when the loop's purpose is to compute a single result: sums, products, string building, search results. Use the statement form (Q66, Q67) when the loop performs side effects like I/O.
See Q66 for while statement form. See Q67 for do-while statement form. See Q80 for for-range expression. See Q82 for for-in expression. See Q68 for switch expression.
Example
defines module qa.flow.while.expression defines function supplyLimit() as pure -> initial as Integer <- rtn as Integer: initial defines program WhileExpressionDemo() stdout <- Stdout() // === WHILE EXPRESSION === limit <- supplyLimit(5) sumResult <- while counter <- 0 with counter < limit <- rtn <- 0 rtn: rtn + counter counter: counter + 1 stdout.println(`While sum 0..4: ${sumResult}`) // === DO-WHILE EXPRESSION === doResult <- do counter <- 0 <- rtn <- 0 rtn: rtn + counter counter: counter + 1 while counter < limit stdout.println(`Do-while sum 0..4: ${doResult}`) // === DO-WHILE AT-LEAST-ONCE === // Even with limit=0, do-while body runs once zeroLimit <- supplyLimit(0) atLeastOnce <- do counter <- 1 <- rtn <- 0 rtn: rtn + counter counter: counter + 1 while counter < zeroLimit stdout.println(`At-least-once result: ${atLeastOnce}`) // === BUILDING A STRING === expectedLength <- supplyLimit(4) builtString <- while n <- 1 with n <= expectedLength <- rtn <- "" if length rtn > 0 rtn: rtn + "-" rtn: rtn + $n n: n + 1 stdout.println(`Built: ${builtString}`)
Common mistakes
E01072 — EK9 has no return statement. While expressions use a declared return variable inside the loop body. The final value is returned implicitly. See ek9 -h E01072 for details.
Incorrect:
total <- 0 counter <- 0 while counter < limit total: total + counter counter: counter + 1 return total
Correct:
sumResult <- while counter <- 0 with counter < limit <- rtn <- 0 rtn: rtn + counter counter: counter + 1
E01070 — EK9 has no break statement. Do-while expressions always run until the condition is false. Structure the while condition to control termination. See ek9 -h E01070 for details.
Incorrect:
total <- 0 counter <- 0 do total: total + counter counter: counter + 1 if counter > 3 break while counter < limit
Correct:
doResult <- do counter <- 0 <- rtn <- 0 rtn: rtn + counter counter: counter + 1 while counter < limit
Other ways to ask this
- How do I use a while loop as an expression in EK9?
- Can a do-while loop return a value in EK9?
- How do while and do-while expression forms work?
Coming from another language?
Java: no while/do-while expression form, must declare accumulator outside loop. Python: no while expression, use list comprehension or itertools for functional accumulation. Rust: loop { break value } returns a value from loop, while and for do not directly return values. Go: no loop expression form, always use external accumulator. Kotlin: no while expression, use generateSequence().takeWhile().fold() for functional equivalent. C#: no while expression, use LINQ for functional accumulation. JavaScript: no while expression, use Array methods for functional patterns. Swift: no while expression, use sequence/reduce patterns. EK9: while and do-while expression with declared return variable, guard variables for loop initialisation, accumulator scoped to loop body.
Keywords: counter, control, isset, compute, null-safe, branch, expression, value, do, while, safe, accumulate, guard, flow, condition