Skip to content

Errors and Result

HollowScript keeps two kinds of failure apart on purpose:

  • A recoverable error is an ordinary value, a Result that holds an error, and the program decides what to do with it.
  • A fault aborts the run. It cannot be caught. Faults are for the things a script has no business recovering from: resource limits, division by zero, a capability failing inside the host.

There is no try, no catch, and no exception. See section 8.1.

Result<T, E> is a built-in enum, Ok(T) or Err(E), built with success(value) and failure(error). The ? postfix operator unwraps an Ok, or, on an Err, returns it immediately from the innermost enclosing function or closure, which must itself return a Result with the identical error type:

uses print
fn half(n: Int): Result<Int, String> {
if mod(n, 2) != 0 {
return failure("${n} is odd")
}
return success(div(n, 2))
}
fn halveTwice(n: Int): Result<Int, String> {
constant once = half(n)?
constant twice = half(once)?
return success(twice)
}
fn show(r: Result<Int, String>): String {
match r {
Ok(n) { return "result ${n}" }
Err(message) { return "error: ${message}" }
}
}
effect print(show(halveTwice(20)))
effect print(show(halveTwice(10)))
constant good: Result<Int, String> = success(4)
constant bad: Result<Int, String> = failure("no")
constant doubled = good.map(fn(n) {
return n * 2
})
effect print("${doubled.unwrapOr(0)} ${bad.unwrapOr(7)} ${bad.isErr()}")

Output:

result 5
error: 5 is odd
8 7 true

halveTwice(20) halves cleanly twice and gets 5. halveTwice(10) halves once to 5, then half(5) fails, and ? sends that Err straight back out of halveTwice without an explicit match. This is the normal shape of a function that chains several things that can fail: unwrap each with ? and let the first failure short-circuit the rest.

Result also has ordinary methods for when you would rather transform a result than branch on it immediately: map, mapError, andThen, unwrapOr, isOk, isErr, ok() and err(). See section 8.3 and section 8.4.

Ignoring a Result silently, an expression statement whose value is a Result and is not followed by ?, is a warning, not an error: the checker assumes it is almost always a mistake, and expects you to either handle it or bind it to a name starting with _ to say you meant to discard it.