How do return values work in EK9 functions?
← Syntax and Structure Rules · Ref: Q917
EK9 uses ONE <- return declaration per function. There is NO return keyword. You declare a named return variable, give it a default value, then update it on different code paths.
BASIC PATTERN
classify() as pure -> score as Integer <- label as String: "average" if score >= 90 label: "excellent" else if score < 40 label: "poor"
The variable 'label' is declared with <- and default "average". Different code paths update it with the : assignment operator. The compiler ensures all paths initialise the variable.
RULES
1. ONE <- per function (not multiple returns)
2. The return variable MUST have a default value or be initialised on ALL paths
3. Use : to update the return variable on conditional paths
4. There is NO return keyword — the named variable is automatically returned
NO EARLY RETURN
Instead of returning early, structure your logic so the return variable gets the right value:
process() as pure -> text as String <- rtn as String: "empty" if text? rtn: text.upperCase()
If text is unset, rtn stays "empty". If set, rtn gets the uppercase version.
MULTIPLE RETURN VALUES
If you need multiple return values, return a record or class:
splitName() as pure -> fullName as String <- parts as NameParts: NameParts()
WRONG PATTERNS
<- a as String: "x" <- b as String: "y" WRONG: only one <- allowed return "hello" WRONG: no return keyword
See Q274 for why return was removed. See Q916 for parameter syntax. See Q50 for declared return variables.
Example
defines module qa.syntaxrules.onereturn defines function // Simple return with default greet() as pure -> name as String <- message as String: "Hello, " + name // Conditional paths update the return variable classify() as pure -> score as Integer <- label as String: "average" excellentThreshold <- 90 poorThreshold <- 40 if score >= excellentThreshold label: "excellent" else if score < poorThreshold label: "poor" // Guard pattern instead of early return safeUpperCase() as pure -> text as String <- rtn as String: "empty" if text? rtn: text.upperCase() defines program OneReturnDemo() stdout <- Stdout() // === Simple return === stdout.println(greet("Steve")) // === Conditional return === stdout.println(`Score 95: ${classify(95)}`) stdout.println(`Score 30: ${classify(30)}`) stdout.println(`Score 60: ${classify(60)}`) // === Guard pattern === stdout.println(`Upper: ${safeUpperCase("hello")}`) stdout.println(`Empty: ${safeUpperCase(String())}`)
Common mistakes
E01083 — EK9 allows only ONE <- return declaration per function. Multiple <- arrows trigger E01083. Declare a single named return variable and update it on different code paths. See ek9 -h E01083 for details.
Incorrect:
<- label as String: "average" <- extra as Integer: 0
Correct:
<- label as String: "average"
Other ways to ask this
- Can I have multiple return statements in EK9?
- How do I declare a return value in EK9?
- What does <- mean for returns in EK9?
Coming from another language?
Java: return statement, multiple returns common. Python: return statement, multiple returns common. Rust: implicit last expression or return. Go: named returns exist but return still needed. Kotlin: return statement. EK9: ONE named return variable with <-, NO return keyword, compiler verifies all paths.
Keywords: value, return, declaration, variable, function, arrow, named, single