How do I migrate complex control flow from Java or Python to EK9?

← Control Flow · Ref: Q148

Five rules map familiar control flow patterns to EK9 equivalents.

RULE 1: BREAK BECOMES HEAD

  results <- cat items | head 3 | collect as List of String

RULE 2: CONTINUE BECOMES FILTER

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

RULE 3: EARLY RETURN BECOMES IF GUARD

  if data <- fetch()
    process(data)

RULE 4: MULTIPLE RETURNS BECOME DECOMPOSITION

  category <- categorise(amount)
  label <- describe(category)

RULE 5: FALLTHROUGH BECOMES COMMA-SEPARATED CASES

  switch code
    case 1, 2, 3
      result: "low"

THE MENTAL MODEL SHIFT

Think 'what do I want?' not 'how do I exit?'. cat items | filter by isValid | head 3 | collect expresses intent directly.

See Q50 for return variables. See Q89 for stream pipelines. See Q125 for head/tail/skip. See Q131 for Python migration. See Q132 for Java migration. See Q144 for control flow philosophy. See Q145 for break/continue replacements. See Q146 for decomposition. See Q147 for fallthrough replacements. See Q288 for break loop migration. See Q289 for return migration. See Q748 for Swift migration.

Example

#!ek9
defines module qa.flow.philosophy.migration

  defines function

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

    isExpensive() as pure
      -> item as String
      <- expensive <- false
      minExpensiveLength <- 6
      expensive: length item > minExpensiveLength

    categorise() as pure
      -> amount as Integer
      <- category as String: "medium"
      highThreshold <- 100
      lowThreshold <- 10
      if amount >= highThreshold
        category: "high"
      else if amount < lowThreshold
        category: "low"

    describe() as pure
      -> category as String
      <- label as String: "standard item"
      switch category
        case "high"
          label: "premium item"
        case "low"
          label: "budget item"
        default
          label: "standard item"

    findByName()
      ->
        target as String
        items as List of String
      <- found as String: String()
      for item in items
        if item == target
          found: item

  defines program

    MigrationDemo()
      stdout <- Stdout()

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

      // === RULE 1: BREAK -> HEAD ===

      firstThree <- cat items | filter by isNonEmpty | head 3 | collect as List of String
      stdout.println(`First 3 non-empty: ${firstThree}`)

      // === RULE 2: CONTINUE -> FILTER ===

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

      // === RULE 3: EARLY RETURN -> GUARD ===

      names <- ["Alice", "Bob", "Charlie"]

      if found <- findByName("Bob", names)
        stdout.println(`Found: ${found}`)

      if found <- findByName("Dave", names)
        stdout.println(`Found: ${found}`)
      else
        stdout.println("Dave not found")

      // === RULE 4: MULTIPLE RETURNS -> DECOMPOSITION ===

      amounts <- [5, 50, 150]
      for amount in amounts
        category <- categorise(amount)
        label <- describe(category)
        stdout.println(`Amount ${amount}: ${label}`)

      // === RULE 5: FALLTHROUGH -> COMMA CASES ===

      codes <- [1, 2, 3, 4, 5]
      for code in codes
        level <- String()
        switch code
          case 1, 2, 3
            level: "basic"
          case 4, 5
            level: "advanced"
          default
            level: "unknown"
        stdout.println(`Code ${code}: ${level}`)

      // === COMBINED: THE MENTAL MODEL SHIFT ===
      // "I want the first 2 expensive items" (not "loop, check, count, break")

      expensive <- cat items | filter by isExpensive | head 2 | collect as List of String
      stdout.println(`First 2 expensive: ${expensive}`)

Common mistakes

E01070 — EK9 has no break statement. Migration Rule 1: break becomes head. Use stream pipelines with head N instead of loop-with-break-at-count. See ek9 -h E01070 for details.

Incorrect:

firstThree <- List() of String
      for item in items
        if isNonEmpty(item)
          firstThree += item
          if length firstThree >= 3
            break

Correct:

firstThree <- cat items | filter by isNonEmpty | head 3 | collect as List of String

E01071 — EK9 has no continue statement. Migration Rule 2: continue becomes filter. Use stream pipelines with filter to keep only matching items. See ek9 -h E01071 for details.

Incorrect:

nonEmpty <- List() of String
      for item in items
        if not isNonEmpty(item)
          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 a default value and conditionally assign. The compiler ensures all paths initialize the return variable. See ek9 -h E01072 for details.

Incorrect:

<- found as String: String()
      return found

Correct:

<- found as String: String()

E01075 — EK9 has no 'new' keyword. Types are instantiated by calling the constructor directly. Java's 'new ArrayList<>()' becomes List() of Type in EK9. See ek9 -h E01075 for details.

Incorrect:

items <- new List("", "apple", "banana", "", "cherry", "date", "elderberry", "fig", "grape")

Correct:

items <- ["", "apple", "banana", "", "cherry", "date", "elderberry", "fig", "grape"]
Other ways to ask this
  • How do I rewrite a Java loop with break and continue in EK9?
  • How do I translate early return patterns to EK9?
  • What is the step-by-step process for converting control flow to EK9?
  • What are the migration rules for converting break, continue, and return to EK9?

Coming from another language?

Java/Python/Rust/Go/JS: break, continue, return, switch fallthrough. EK9: five rules map to stream pipelines, guards, function decomposition, comma-separated cases.

Keywords: branch, break, condition, continue, control, convert, flow, java, mental, migrate, migration, model, pattern, python, return, rewrite, rule, step, swift, translate