Option, Result, and Error
API summary (generated from the Beans source by npm run coverage): 3 types · 11 instance methods · 2 public fields · 4 prelude values.
Beans has no null and no exceptions. Instead it gives you two builtin enums and one builtin class for “maybe” and “failed” answers. This page explains all three and the tools to work with them. For the wider picture, see error handling in the language guide.
Option<T>
Section titled “Option<T>”Option<T> is a value that may be missing. It is a builtin enum with two variants:
some(value: T): there is a value.none: there is nothing.
You make one with the prelude names some and none, and read it with match:
let found: Option<int> = some(42)match found { some(v) => io.println("got {v}"), none => io.println("nothing"),}Result<T, E>
Section titled “Result<T, E>”Result<T, E> is either a value or an error. It is a builtin enum:
ok(value: T): success, with a value.err(error: E): failure, with an error.
Result<T> on its own means Result<T, Error>, using the standard Error type.
fn parse(s: string) -> Result<int> { s.to_int()}Error is the standard builtin error class. It has these fields:
msg: string: a human-readable message.kind: string: a short slug naming the kind of error, like"eof".- a
cause: an optional underlying error.
some, none, ok, err are prelude names
Section titled “some, none, ok, err are prelude names”some, none, ok, and err are ordinary names from the prelude. They are not
keywords. You call them like functions.
Ways to make an err:
| Form | Meaning |
|---|---|
err(message) | an Error with that message |
err(message, kind) | an Error with a message and a kind slug |
err(value) | a custom error type, for your own E |
fn read_more() -> Result<Bytes> { err("closed", "eof")}The ? operator
Section titled “The ? operator”The ? operator unwraps a Result. If the value is err, ? returns that error
up to the caller right away. If it is ok, ? gives you the inner value.
fn total(a: string, b: string) -> Result<int> { let x: int = a.to_int()? let y: int = b.to_int()? ok(x + y)}Use match when you want to handle both arms yourself instead.
panic(message: string) is a prelude function for an error you cannot recover
from. It reports the call location and your message, exits with status 3, and never
returns. It does not run defers.
panic("unreachable state")Prefer Option and Result for errors you can handle. Use panic only for bugs
that should never happen. See Prelude functions.
Option methods
Section titled “Option methods”Option<T>.or(T) -> TOption<T>.expect(string) -> TOption<T>.is_some() -> boolOption<T>.is_none() -> boolor(fallback)returns the value, orfallbackifnone.expect(msg)returns the value, or panics withmsgifnone.is_some()is true when there is a value;is_none()is true when there is not.
Option<T> also has three higher-order combinators, generic over the closure’s
result:
map(fn(T) -> U) -> Option<U>appliesfnto the value if present.and_then(fn(T) -> Option<U>) -> Option<U>applies anfnthat itself returns anOption.filter(fn(T) -> bool) -> Option<T>keeps the value only iffnreturns true.
let n: int = "7".to_int().or(0)let name: Option<string> = some("ann")let upper: Option<string> = name.map(fn(s: string) -> string { s.to_upper() })Result methods
Section titled “Result methods”Result<T>.or(T) -> TResult<T>.expect(string) -> TResult<T>.is_ok() -> boolor(fallback)returns the value, orfallbackiferr.expect(msg)returns the value, or panics withmsgiferr.is_ok()is true on success.
Result<T> has three higher-order combinators as well:
map(fn(T) -> U) -> Result<U>appliesfnto the value on success.and_then(fn(T) -> Result<U>) -> Result<U>applies anfnthat itself returns aResult.recover(fn(Error) -> T) -> Tturns an error into a value.
let count: int = "42".to_int().recover(fn(e: Error) -> int { 0 })A worked example
Section titled “A worked example”? propagates the first error; match handles both arms; err(msg, kind) sets a
kind slug you can read back off Error:
import std.io
fn parse_qty(s: string) -> Result<int> { let n: int = s.to_int()? if n < 0 { return err("quantity cannot be negative", "invalid") } return ok(n)}
fn main() { match parse_qty("42") { ok(n) => io.println("qty {n}"), err(e) => io.println("{e.kind}: {e.msg}"), } match parse_qty("-3") { ok(n) => io.println("qty {n}"), err(e) => io.println("{e.kind}: {e.msg}"), }
let fallback: int = parse_qty("nope").or(0) io.println("fallback {fallback}")}See also
Section titled “See also”- Error handling in the language guide.
- Prelude functions,
panicin full. - string,
to_int,to_float,to_decimalreturnResult.