Errors and Result
HollowScript keeps two kinds of failure apart on purpose:
- A recoverable error is an ordinary value, a
Resultthat 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 5error: 5 is odd8 7 truehalveTwice(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.