How do I exit a loop early or skip iterations in EK9?

← Control Flow · Ref: Q145

EK9 has no break or continue. Stream pipelines with head, filter, and skip are the designed replacements.

REPLACING BREAK WITH HEAD

Where other languages use a loop with break to find the first match, EK9 uses head 1:

  first <- cat items | filter by isLong | head 1 | collect as List of String

The head operation stops the pipeline after N items. No elements beyond that point are processed.

REPLACING CONTINUE WITH FILTER

Where other languages skip unwanted items with continue, EK9 uses filter:

  valid <- cat items | filter by isNonEmpty | collect as List of String

The filter operation passes only items that match the predicate. Items that do not match are discarded.

REPLACING COUNTED BREAK WITH HEAD N

Where other languages count items and break at a limit, EK9 uses head N:

  topFive <- cat items | sort | head 5 | collect as List of String

This takes exactly 5 items and stops. No counter variable, no break condition.

REPLACING SKIP-AHEAD WITH SKIP

Where other languages use continue with a counter to skip initial items, EK9 uses skip:

  afterHeader <- cat lines | skip 3 | collect as List of String

This discards the first 3 elements and passes the rest through.

WHEN LOOPS ARE STILL APPROPRIATE

For-in and for-range loops are still the right tool for side effects that process every item:

  for item in items
    stdout.println(`Processing: ${item}`)

Loops work when you need to process ALL items and perform actions. Streams work when you need to select, transform, or limit.

COMBINING OPERATIONS

Pipeline operations compose naturally:

  results <- cat items | filter by isValid | skip 2 | head 3 | collect as List of String

This filters, skips 2 valid items, then takes the next 3. Each operation has a single responsibility.

See Q64 for for-range loops. See Q65 for for-in loops. See Q89 for stream pipeline basics. See Q125 for head, tail, and skip details. See Q131 for Python comprehension migration. See Q133 for tee and uniq operations. See Q144 for why break and continue were removed. See Q282 for nested loop patterns. See Q288 for before and after migration examples.

Example

defines module qa.flow.philosophy.replacingbreak

  defines function

    isLong() as pure
      -> item as String
      <- long <- false
      maxItems <- 5
      long: length item > maxItems

    isNonEmpty() as pure
      -> item as String
      <- nonEmpty as Boolean: length item > 0

    isValid() as pure
      -> item as String
      <- valid <- false
      divisor <- 2
      valid: length item > divisor

  defines program

    ReplacingBreakContinueDemo()
      stdout <- Stdout()

      items <- ["", "hi", "apple", "banana", "", "cherry", "date", "elderberry", "fig"]

      // === REPLACING BREAK: FIND FIRST LONG ITEM ===

      firstLong <- cat items | filter by isLong | head 1 | collect as List of String
      stdout.println(`First long item: ${firstLong}`)

      // === REPLACING CONTINUE: SKIP EMPTY STRINGS ===

      nonEmpty <- cat items | filter by isNonEmpty | collect as List of String
      stdout.println(`Non-empty: ${nonEmpty}`)

      // === REPLACING COUNTED BREAK: TOP 3 ===

      topThree <- cat items | filter by isNonEmpty | sort | head 3 | collect as List of String
      stdout.println(`Top 3 sorted: ${topThree}`)

      // === REPLACING SKIP-AHEAD ===

      afterSkip <- cat items | filter by isValid | skip 2 | collect as List of String
      stdout.println(`After skipping 2 valid: ${afterSkip}`)

      // === COMBINING: FILTER + SKIP + HEAD ===

      window <- cat items | filter by isValid | skip 1 | head 3 | collect as List of String
      stdout.println(`Window (skip 1, head 3): ${window}`)

      // === LOOP FOR SIDE EFFECTS ===

      stdout.println("Processing all valid items:")
      for item in items
        if length item > 0
          stdout.println(`  -> ${item}`)

Common mistakes

E01070 — EK9 has no break statement. Use stream pipelines with head 1 to find the first matching item. The pipeline stops processing after the first match. See ek9 -h E01070 for details.

Incorrect:

firstLong <- String()
      for item in items
        if isLong(item)
          firstLong: item
          break

Correct:

firstLong <- cat items | filter by isLong | head 1 | collect as List of String

E01071 — EK9 has no continue statement. Use stream pipelines with filter to keep only items matching a predicate, replacing the skip-with-continue pattern. See ek9 -h E01071 for details.

Incorrect:

nonEmpty <- List() of String
      for item in items
        if length item == 0
          continue
        nonEmpty += item

Correct:

nonEmpty <- cat items | filter by isNonEmpty | collect as List of String

E01072 — EK9 has no return statement. Declare the return variable with '<-' and assign it conditionally. The compiler ensures all paths initialise the return variable. See ek9 -h E01072 for details.

Incorrect:

<- long <- false
      return true

Correct:

<- long <- false
Other ways to ask this
  • What replaces break and continue in EK9?
  • How do I find the first match without break in EK9?
  • How do I skip items in a loop without continue in EK9?
  • How do I replace break and continue with stream operations in EK9?

Coming from another language?

Java: break to exit loop, continue to skip iteration, Streams with limit() and skip() as alternative. Python: break to exit loop, continue to skip, list comprehensions with conditions as alternative. Rust: break to exit loop, continue to skip, iterators with take() and skip() as alternative. Go: break to exit loop, continue to skip, no built-in stream alternative. C/C++: break and continue in loops. Kotlin: break and continue, sequences with take() and drop(). JavaScript: break and continue, array methods filter() and slice(). EK9: no break or continue, stream pipelines with head (replaces break), filter (replaces continue), skip (replaces counted skip), and tail (last N).

Keywords: stream, control, loop, early, break, match, condition, filter, skip, flow, pipeline, first, head, continue, iteration, alternative, replace, migrate, branch, exit