Can a for-in loop return a value (for-in as expression)?

← Control Flow · Ref: Q82

Yes. A for-in loop can return a value by declaring a return variable inside the loop body. This is EK9's equivalent of fold/reduce operations in functional languages.

BASIC FOR-IN EXPRESSION

Concatenate all items in a list:

  joined <- for item in items
    <- rtn <- ""
    rtn: rtn + item

The outer '<- joined' captures the loop result. The inner '<- rtn <- ""' declares the return variable initialised to an empty string. Each iteration appends the current item to 'rtn'. After the loop completes, the final string is assigned to 'joined'.

SUM A LIST OF NUMBERS

Reduce a list to its sum:

  numbers <- [10, 20, 30, 40]
  total <- for n in numbers
    <- rtn <- 0
    rtn: rtn + n

Result: 100. This is the equivalent of numbers.stream().reduce(0, Integer::sum) in Java or numbers.iter().sum() in Rust.

FIND MAXIMUM

Find the largest value in a list:

  largest <- for n in numbers
    <- rtn <- Integer()
    if ~rtn? or n > rtn
      rtn: n

The return variable starts unset (Integer()). The first iteration sets it to the first element. Subsequent iterations update it only if the current element is larger.

BUILDING WITH SEPARATOR

Join strings with a comma separator:

  csv <- for name in names
    <- rtn <- ""
    if length rtn > 0
      rtn: rtn + ", "
    rtn: rtn + name

Result: 'Alice, Bob, Charlie'.

STATEMENT VS EXPRESSION

The statement form (see Q65) executes code for side effects like printing. The expression form computes a single result from the collection. Use expression form when the loop's purpose is to accumulate, reduce, or transform.

See Q65 for for-in statement form. See Q68 for switch expression. See Q80 for for-range expression. See Q81 for while/do-while expressions. See Q89 for stream pipeline basics. See Q122 for stream collect as aggregation. See Q237 for streams vs loops decision guide.

Example

defines module qa.flow.forin.expression

  defines program

    ForInExpressionDemo()
      stdout <- Stdout()

      // === CONCATENATE STRINGS ===

      words <- ["Hello", " ", "World"]
      joined <- for word in words
        <- rtn <- ""
        rtn: rtn + word
      stdout.println(`Joined: ${joined}`)

      // === SUM NUMBERS ===

      numbers <- [10, 20, 30, 40]
      total <- for n in numbers
        <- rtn <- 0
        rtn: rtn + n
      stdout.println(`Sum: ${total}`)

      // === JOIN WITH SEPARATOR ===

      names <- ["Alice", "Bob", "Charlie"]
      csv <- for name in names
        <- rtn <- ""
        if length rtn > 0
          rtn: rtn + ", "
        rtn: rtn + name
      stdout.println(`Names: ${csv}`)

      // === COUNT MATCHING ITEMS ===

      scores <- [85, 42, 91, 67, 73, 95]
      passingGrade <- 70
      passing <- for s in scores
        <- rtn <- 0
        if s >= passingGrade
          rtn: rtn + 1
      stdout.println(`Passing scores: ${passing}`)

Common mistakes

E01072 — EK9 has no return statement. For-in expressions use a declared return variable scoped to the loop body. The final value is returned implicitly. See ek9 -h E01072 for details.

Incorrect:

total <- 0
      for n in numbers
        total: total + n
      return total

Correct:

total <- for n in numbers
        <- rtn <- 0
        rtn: rtn + n
Other ways to ask this
  • How do I use a for-in loop as an expression in EK9?
  • How do I reduce a collection to a single value in EK9?
  • How does the for-in expression form work?

Coming from another language?

Java: stream().reduce(identity, accumulator) or stream().collect() for fold/reduce patterns. Python: functools.reduce(fn, iterable, initial) or list comprehension. Rust: iterator.fold(init, |acc, x| acc + x) or .sum()/.collect(). Go: no fold primitive, must use for-range with external accumulator. Kotlin: list.fold(initial) { acc, item -> acc + item } or list.reduce(). C#: list.Aggregate(seed, (acc, x) => acc + x) LINQ method. JavaScript: array.reduce((acc, x) => acc + x, initial). Swift: array.reduce(0, +) or array.reduce(into:). EK9: for-in expression with declared return variable, natural fold/reduce pattern, accumulator scoped to loop body, no external variable needed.

Keywords: accumulate, branch, control, flow, condition, fold, in, collection, migrate, expression, compute, value, for, reduce