Skip to content

Results

Calibre uses result types for error-aware computations.

A result type is written as Err!Ok, where the left side is the error type and the right side is the ok type.

const parse_and_add := fn (txt : str, extra : int) -> str!int => {
let n := try txt as int;
ok(n + extra);
};

In str!int, str is the error type and int is the successful value type.

Results are commonly created with ok(...) and err(...).

ok(10);
err("something went wrong");

You can inspect results with pattern matching.

match parse_and_add("50", 7) {
.Ok : value => print(value),
.Err : message => print(message)
};

Calibre also provides the try keyword for working with results more conveniently.

Here, if txt as int fails, the error is propagated instead of continuing.

const parse_and_add := fn (txt : str, extra : int) -> str!int => {
let n := try txt as int;
ok(n + extra);
};

try can also take a fallback expression with =>.

let number := try "64" as int => 0;

In this form, if the result is successful, the success value is produced. If it fails, the expression after => is used instead.

You can also bind the error value with : name =>.

In this form, the error is bound to e and can be inspected or transformed before choosing what to do next.

let file := try File.open_read("input.txt") : e => {
panic(e);
};

These forms are all valid:

let a := try some_result;
let b := try some_result => fallback_value;
let c := try some_result : err_value => fallback_expression;

Use plain try value; when you want to propagate failure, try value => ... when you want a fallback, and try value : err => ... when you also need access to the error itself.

Results come with standard helper methods.

let parsed := parse_and_add("50", 7);
print(parsed.is_ok());
print(parsed.is_err());
print(parsed.unwrap_or(0));

You can transform results with methods like .map(...) and .map_err(...).

let res1 := ok(7).map(fn (x : int) -> int => x * 2);
let res2 := err("oops").map_err(fn (e : str) -> str => "ERR: " & e);

Use results when an operation can fail and you want that possibility to be visible in the type system.