How do I process items until a condition is met without break?

← Control Flow Without break/continue/return · Ref: Q287

In Java you write: while(true) { item = next(); if (done(item)) break; process(item); }. EK9 replaces this with guard-driven termination: the while loop condition itself controls when to stop.

THE PROBLEM

Processing items until a termination condition is the most common use of while(true) with break. The break is buried inside the loop body, making the termination condition hard to find.

PATTERN 1: WHILE WITH GUARD VARIABLE

Use a Boolean flag that controls the while loop:

  done <- Boolean(false)
  idx <- 0
  while ~done? and idx < length items
    item <- items.getOrDefault(idx, "")
    if item == "STOP"
      done: true
    else
      process(item)
    idx: idx + 1

The termination condition is in the while expression, not buried in the body.

PATTERN 2: COUNTING WITH FOR-RANGE

When processing up to a known maximum:

  for count in 1 ... maxItems
    if ~finished?
      item <- getItem(count)
      if isTerminal(item)
        finished: true
      else
        process(item)

PATTERN 3: STREAM WITH HEAD

When you want the first N items that satisfy a condition:

  results <- cat items | filter by isActive | head 10 | collect as List of String

The pipeline stops after 10 active items. No loop, no break, no counter.

GUARD-DRIVEN VS BREAK-DRIVEN

Break-driven: the loop runs forever, break is the only way out. The termination logic is scattered through the body.
Guard-driven: the while condition states exactly when the loop ends. The body focuses on processing.

See Q66 for while loops. See Q144 for no break. See Q125 for head.

Example

defines module qa.without.processuntil

  defines function

    isActive() as pure
      -> item as String
      <- active as Boolean: item <> "STOP" and length item > 0

    processWithLimit()
      ->
        dataItems as List of String
        readLimit as Integer
      <- itemsRead as Integer: 0

      for pos in 0 ... length dataItems - 1
        if itemsRead < readLimit
          itemsRead: itemsRead + 1

  defines program

    ProcessUntilDemo()
      stdout <- Stdout()

      // === PATTERN 1: WHILE WITH GUARD VARIABLE ===

      items <- ["alpha", "bravo", "charlie", "STOP", "delta", "echo"]
      done <- Boolean(false)
      idx <- 0
      processed <- 0
      while ~done and idx < length items
        item <- items.getOrDefault(idx, "")
        if item == "STOP"
          done: true
        else
          stdout.println(`Processing: ${item}`)
          processed: processed + 1
        idx: idx + 1
      stdout.println(`Processed ${processed} items before STOP`)

      // === PATTERN 2: COUNTING WITH FOR-RANGE ===

      numbers <- [10, 20, 30, 40, 50, 60, 70]
      runningTotal <- 0
      totalLimit <- 100
      exceeded <- Boolean(false)
      for count in 0 ... length numbers - 1
        if ~exceeded
          currentNum <- numbers.getOrDefault(count, 0)
          if runningTotal + currentNum > totalLimit
            exceeded: true
          else
            runningTotal: runningTotal + currentNum
      stdout.println(`Running total (stopped before exceeding 100): ${runningTotal}`)

      // === PATTERN 3: STREAM WITH HEAD ===

      allItems <- ["", "alpha", "bravo", "", "charlie", "STOP", "delta", "echo", "foxtrot"]
      activeItems <- cat allItems | filter by isActive | head 3 | collect as List of String
      stdout.println(`First 3 active items: ${activeItems}`)

      // === BOUNDED PROCESSING WITH INDEX ===

      dataItems <- ["read1", "read2", "read3", "read4", "read5"]
      itemsRead <- processWithLimit(dataItems, 3)
      stdout.println(`Bounded read processed ${itemsRead} items`)

Common mistakes

E01070 — EK9 has no break statement. To stop processing when a condition is met, set a guard flag variable and check it in the while condition. See ek9 -h E01070 for details.

Incorrect:

break

Correct:

done: true
Other ways to ask this
  • How do I replace while(true) with break-on-condition in EK9?
  • How do I consume items until done without break in EK9?
  • How do I write a processing loop that stops on a condition in EK9?

Coming from another language?

Java: while(true) { if (done) break; } or do-while with condition. Python: while True: if done: break. Rust: loop { if done { break; } } or while !done. Go: for { if done { break } }. Kotlin: while(true) { if (done) break }. JavaScript: while(true) { if (done) break; }. EK9: while with guard expression or flag variable, for-range for bounded processing, stream head for take-first-N.

Keywords: alternative, migrate, done, no-return, consume, process, until, guard, null-safe, stop, exhaust, terminate, no-break, loop, safe, isset, while, condition