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