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