Heroes / Examples / 03-fallible
examples/gallery/03-fallible.hero
Return failures as values and handle them explicitly.
- 54 lines
A function returning T? gives either a T value or an error. fail creates the error, ? returns it to the caller, and match handles success and failure. Heroes has no exceptions: the return type says whether a call can fail.
Run it
These files introduce the language one feature at a time. This page shows the program and not a result, because no test compares their output byte for byte yet.
The program
## Failure is a value
#
# There is no `null` and there are no exceptions. A `T?` is a `T` or an
# error, `fail` makes one, `?` hands it to the caller, and `match` is the
# general way to look.
# Parses a decimal digit. Fails on anything else.
function digit_of(c: u8) -> i64?
if c < '0' || c > '9'
return fail(code: "not_a_digit", msg: "expected 0-9")
return ok(to_i64(c - '0').must())
# Reads a whole non-negative number. Empty input is an error, not a zero.
function number_of(text: str) -> i64?
if text.len() == 0
return fail(code: "empty", msg: "there is nothing to read")
total: i64 @= 0
for i in range(from: 0, to: text.len())
total @ total * 10 + digit_of(text[i])?
return ok(total)
# The `?` above is the whole point: three lines, no error handling in sight,
# and the first bad character stops everything.
function average_of(parts: [str]) -> i64?
sum: i64 @= 0
for p in parts
sum @ sum + number_of(p)?
if parts.len() == 0
return fail(code: "empty", msg: "no parts to average")
return ok(sum / parts.len())
# Four ways to read a fallible value, in the order you reach for them.
function report(text: str) -> str
match number_of(text)
.ok v => return "read " + v.to_str()
.err e => return "failed: " + e.code + " (" + e.msg + ")"
function first_or_zero(parts: [str]) -> i64
return number_of(parts[0]).default(0)
test "a good number and a bad one"
assert number_of("120").must() == 120
assert number_of("12x").is_err()
assert report("7") == "read 7"
assert first_or_zero(["oops"]) == 0
function main()
print(report("42"))
print(report("4b2"))
print(average_of(["10", "20", "30"]).default(-1))
fingerprint sha256 24f91adb4042 · 1 file · index.json
Next: 04-loops. All the examples. ← Previous: 02-tokens
Run one yourself: the four commands. Learn the language, or read the full specification in one file.