Why must Result be used with two different types?
← Generics · Ref: Q652
EK9 requires Result to be parameterised with two DIFFERENT types. Using 'Result of (String, String)' is an error because the compiler cannot distinguish success from failure when both have the same type.
DIFFERENT TYPES REQUIRED
The ok type and error type must differ:
Result of (Integer, String) // correct: Integer ok, String error Result of (String, String) // ERROR E06190: same types
WHY REQUIRED
Result's purpose is to carry EITHER a success value OR an error value. If both are the same type, there is no way to distinguish which state the Result is in. The type system loses its ability to guarantee safety.
CORRECT PATTERNS
Use distinct types for success and error:
Result of (UserRecord, String) // success: record, error: message Result of (Integer, ErrorCode) // success: count, error: enum Result of (Float, Exception) // success: value, error: exception
CREATING RESULTS
Use the ok or error constructor:
okResult <- Result(42, String()) // ok result errResult <- Result(Integer(), "failed") // error result
See Q48 for Result basics. See Q198 for built-in generics. See Q104 for error handling patterns.
Example
defines module qa.genericsdeep.resultdifferenttypes defines function <?- Correct: Result with different ok and error types. Integer for success value, String for error message. -?> safeDivide() as pure -> numerator as Integer denominator as Integer <- rtn as Result of (Integer, String): Result(Integer(), "not calculated") if denominator == 0 rtn: Result(Integer(), "division by zero") else rtn: Result(numerator / denominator, String()) <?- Correct: Result with custom type and String error. -?> parseScore() as pure -> input as String <- rtn as Result of (Float, String): Result(Float(), "not parsed") if input? rtn: Result(Float(input), String()) defines program ResultDifferentTypesDemo() stdout <- Stdout() // === SUCCESSFUL DIVISION === divResult <- safeDivide(numerator: 10, denominator: 3) stdout.println(`Division result set: ${divResult?}`) // === DIVISION BY ZERO === zeroResult <- safeDivide(numerator: 10, denominator: 0) stdout.println(`Zero division set: ${zeroResult?}`) // === PARSE RESULT === scoreResult <- parseScore("95.5") stdout.println(`Parse result set: ${scoreResult?}`)
Common mistakes
E06190 — Result must be parameterised with two different types so the compiler can distinguish success from error. Using the same type for both (e.g., Result of (String, String)) triggers E06190. See ek9 -h E06190 for details.
Incorrect:
rtn as Result of (String, String): Result(String(), "not calculated")
Correct:
rtn as Result of (Integer, String): Result(Integer(), "not calculated")
Other ways to ask this
- What is E06190 Result must have different types?
- Can I use Result with the same type for success and error?
- How does EK9 prevent Result type ambiguity?
Coming from another language?
Java: no built-in Result type. Rust: Result<T, E> allows same types (Result<String, String> is valid). Go: multiple return values (value, error). Kotlin: Result<T> wraps only success, uses exceptions for errors. EK9: Result of (OK, ERR) requires OK and ERR to be different types for unambiguous state.
Keywords: ambiguity, E06190, ok, success, type-parameter, result, error, types, generic, guard, different