Option and Result¶
Option represents a value that may be missing. Result represents an operation that may have failed. Both make you consider the other outcome instead of assuming a value exists. No import is needed.
import system;
fun main() {
let maybe: Option<int> = Some(3);
System.println(maybe.unwrap_or(0));
let parsed = int.parse("42"); // Result<int, ParseError>
switch (parsed) {
Ok(n) => System.println(n),
Err(e) => System.println(e.message()),
}
}
Option<T> — Some(value) or None¶
| Method | Meaning |
|---|---|
is_some() / is_none() |
which arm? |
unwrap_or(fallback) |
value, or a default |
unwrap() / expect(msg) |
value, or panic |
unwrap_or_else(f) |
value, or call f |
filter(pred) / ok_or(err) |
keep / lift into Result |
map(f) |
transform the inner value |
and_then(f) |
chain another Option |
or(other) |
this, or other if None |
Unpack with switch when both arms matter.
Result<T, E> — Ok(value) or Err(error)¶
| Method | Meaning |
|---|---|
is_ok() / is_err() |
which arm? |
unwrap_or(fallback) |
value, or a default |
unwrap() / expect(msg) / unwrap_err() |
panic on the other arm |
ok() |
Option of the success value |
map(f) / map_err(f) |
transform success or error |
and_then(f) |
chain another Result |
File and parse APIs return Result. In an async function (or any function that itself returns Result), ? forwards Err to the caller.
? — try-propagation¶
expr? unwraps Ok or returns Err from the current function. The function’s return type must be a Result.
Option and Result do not mix: ? on an Option needs the enclosing function to return a matching Option. ? on a Result rebuilds Err at the function’s Result type: E may widen when the operand’s error implements the function’s error interface (IoError → Error), but there is no general conversion between unrelated error types. Bridge those explicitly:
let first = first_line(text).ok_or(ParseError.invalid("empty input"))?; // Option → Result
let n = int.parse(text).map_err(fun(e: ParseError): ConfigError => ConfigError.from_parse(e))?;
A Result<T, ConcreteError> is also assignable to Result<T, Error> when ConcreteError implements Error. Use map_err when the payload would change representation (a value struct boxed into an interface).
? in main¶
main may return Result<T, E>, so ? works at the top level. An Err that reaches main is printed to standard error as Error: <e> and the process exits 1:
import system;
fun parse_port(borrow text: string): Result<int, ParseError> {
let port = int.parse(text)?;
if port < 1 || port > 65535 {
return Result.Err(ParseError.invalid("port out of range: " + port.to_string()));
}
return Result.Ok(port);
}
fun main(): Result<Unit, ParseError> {
let port = parse_port("8080")?;
System.println("listening on " + port.to_string());
let bad = parse_port("not-a-number")?; // Err: returns from main right here
System.println("never reached " + bad.to_string());
} // falling off the end of main is an implicit Result.Ok(Unit())
An operation with nothing to return uses Unit as its success value, so it returns Result<Unit, E> and succeeds with Result.Ok(Unit()). main alone may fall off the end when it returns Result<Unit, E>, which the compiler treats as return Result.Ok(Unit()); — an explicit one stays legal, and any other Result<T, E> still requires a return on every path.
async fun main(): Result<T, E> works the same way, and ? binds to the awaited value, so no parentheses are needed:
async fun main(): Result<Unit, IoError> {
let text = File.read("config.json").await?;
System.println(text);
}
An Option main is rejected — bridge it with ok_or as above. main(): int is also allowed, and returns the process exit code directly; falling off the end means return 0.
Errors¶
Types that implement Error have .message() and .code(). Common ones: ParseError (bootstrap), ArgumentError (import system;), IoError (system.io).
Flatten nested optional values¶
Use and_then to turn Option<Option<T>> into Option<T>. It keeps the inner optional value when the outside is Some, and returns None when the outside is None.
import system;
fun main() {
let inner: Option<int> = Some(7);
let nested: Option<Option<int>> = Some(inner);
let value: Option<int> = nested.and_then((item: Option<int>) => item);
System.println(value.unwrap_or(0));
}
This prints 7.
The library also declares the static helper Option.flatten, but the current build rejects calls to it. Use the example above until that helper is available.
Recover from a failure¶
result.or_else(handler) calls the handler only for Err. The handler receives the error and returns a new Result with the same success type. It can provide a replacement success value or return another error. An Ok passes through unchanged.
Use unwrap_or for a fixed fallback value, map_err to change an error, and or_else when recovery itself can succeed or fail.
See the Option signatures, Result signatures, and error guide.