How do I convert functions with multiple return statements to EK9?
← Control Flow Without break/continue/return · Ref: Q289
This shows four common multi-return patterns and their EK9 equivalents side by side.
SCENARIO 1: GUARD CLAUSE RETURNS
Java: if (name == null || name.isEmpty()) return "invalid"; if (name.length() > 50) return "too long"; return "ok";
EK9 equivalent uses if/else with declared return:
validateName() as pure -> name as String <- status as String: "ok" if length name == 0 status: "invalid" else if length name > 50 status: "too long"
The declared return starts with a default. Conditions modify it. Every path is visible.
SCENARIO 2: LOOKUP WITH DEFAULT
Java: for (String s : items) { if (s.equals(target)) return s; } return "not found";
EK9 equivalent uses unset return + for loop + :=? default:
lookup()
-> items as List of String, target as String
<- found as String: String()
for item in items
if item == target and ~found?
found :=? item
The caller checks if found? and uses a default if not. No loop break, no return inside loop.
SCENARIO 3: MULTI-BRANCH CLASSIFICATION
Java: if (score >= 90) return "A"; if (score >= 80) return "B"; if (score >= 70) return "C"; return "F";
EK9 equivalent uses declared return with conditional assignment:
grade() as pure -> score as Integer <- letter as String: "F" if score >= 90 letter: "A" else if score >= 80 letter: "B" else if score >= 70 letter: "C"
SCENARIO 4: TERNARY CHAIN
Java: return a > 0 ? "positive" : a < 0 ? "negative" : "zero";
EK9 equivalent uses :=? chain:
describe() as pure -> num as Integer <- label as String? if num > 0 label :=? "positive" else if num < 0 label :=? "negative" else label :=? "zero"
Each branch assigns exactly once via :=?. The compiler verifies all paths set the value.
THE PATTERN
Every multi-return function becomes: declare the return variable with a sensible default, then use if/else to modify it. The compiler verifies every path initialises the return.
See Q50 for declared returns. See Q146 for decomposition. See Q274 for AI return patterns. See Q148 for migration.
Example
defines module qa.without.migratereturn defines function // Scenario 1: Guard clause returns validateName() as pure -> name as String <- status as String: "ok" maxNameLength <- 50 if length name == 0 status: "invalid" else if length name > maxNameLength status: "too long" // Scenario 2: Lookup with default lookup() -> items as List of String target as String <- found as String: String() for item in items if item == target and ~found? found :=? item // Scenario 3: Multi-branch classification grade() as pure -> score as Integer <- letter as String: "F" excellentMinScore <- 90 goodMinScore <- 80 averageMinScore <- 70 if score >= excellentMinScore letter: "A" else if score >= goodMinScore letter: "B" else if score >= averageMinScore letter: "C" // Scenario 4: Ternary chain describeSign() as pure -> num as Integer <- label as String? if num > 0 label :=? "positive" else if num < 0 label :=? "negative" else label :=? "zero" defines program MigrateReturnDemo() stdout <- Stdout() // === SCENARIO 1: GUARD CLAUSE RETURNS === stdout.println(`Empty name: ${validateName("")}`) stdout.println(`Long name: ${validateName("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz")}`) stdout.println(`Valid name: ${validateName("Alice")}`) // === SCENARIO 2: LOOKUP WITH DEFAULT === fruits <- ["apple", "banana", "cherry"] if result <- lookup(fruits, "banana") stdout.println(`Found: ${result}`) missing <- lookup(fruits, "mango") if ~missing? stdout.println("Mango not found, using default") // === SCENARIO 3: MULTI-BRANCH CLASSIFICATION === scores <- [95, 85, 75, 55] for score in scores stdout.println(`Score ${score}: grade ${grade(score)}`) // === SCENARIO 4: TERNARY CHAIN === numbers <- [42, -7, 0] for num in numbers stdout.println(`${num} is ${describeSign(num)}`)
Common mistakes
E50001 — A pure function cannot call non-pure methods like stdout.println(). Pure functions must be free of side effects. See ek9 -h E50001 for details.
Incorrect:
grade() as pure -> score as Integer <- letter as String: "F" stdout.println(score)
Correct:
grade() as pure -> score as Integer <- letter as String: "F"
Other ways to ask this
- What are before and after examples for converting multiple returns to EK9?
- How do I migrate early return guard clauses to EK9?
- How do I replace ternary chains and multi-return functions in EK9?
Coming from another language?
Java: return in every branch, ternary operator for simple cases, guard clauses at top. Python: return in each branch, or pattern for defaults. Rust: implicit return from last expression in each branch, or early return with ?. Go: return in each branch, error return pattern. Kotlin: return or when expression. Swift: return or switch expression. EK9: declared return variable, if/else modifies it, :=? for pure functions, compiler verifies all paths.
Keywords: function, declared, multiple, migrate, named, classification, ternary, return, before, after, null-safe, isset, no-return, safe, no-break, refactor, alternative, convert, guard