Error Handling

Hush implements two error mechanisms: panics and errors.

Panic

A Panic is an irrecoverable1 error, and will occur when there is a logic issue in your code. Panics will cause the whole program to crash, and execution will be terminated.

1. let x = 1 / 0
2. std.print(x)

Running the above script, you’ll get:

1. Panic in <stdin> (line 2, column 10): division by zero

Examples of errors that cause a panic:

  • Syntax error.
  • Integer division by zero.
  • Index out of bounds.
  • Attempt to call a value that is not a function.
  • Missing or exceeding arguments in function call.

Error

Recoverable errors may be expressed through values of the error type. This is a special type in the language, and it is the only which cannot be expressed through a literal. Values of the error type can only be created using the std.error function, which expects a string description and a arbitrary context:

1. function check_limit(x)
2. if x > 10 then
3. std.error("x cannot be bigger than 10", x)
4. else
5. x
6. end
7. end

One can then check whether the function has returned an error:

1. let result = check_limit(11)

3. if std.type(result) == "error" then
4. std.print("Error: ", result)
5. else
6. std.print("Success: ", result)
7. end

The description and context fields can be accessed as in a dictionary, but unlike in dictionaries, those cannot be assigned to:

1. let error = std.error("oh no!", 42)

3. std.print(error.description) # oh no!

5. error.description = "you shouldn't do that!" # panic

Examples of errors should be recoverable:

  • File not found.
  • Insufficient permission
  • Invalid format
  • Command not found
  • Command returned non-zero exit status

Try operator

The try (?2) operator may be used to early return from a function if an error occurs. It is nothing but syntax sugar for an if expression, and therefore it may be used in any expression:

1. function safe_div_mod(x, y)
2. if y == 0 then
3. std.error("division by zero", nil)
4. else
5. @[ div: x / y, mod: x % y ]
6. end
7. end

9. # The following are equivalent:

11. function foo()
12. let result = safe_div_mod(5, 0)

14. let value = if std.type(result) == "error" then
15. return result
16. else
17. result
18. end

20. std.print(value)
21. end

23. function bar()
24. let value = safe_div_mod(5, 0)?
25. std.print(value) # this won't be executed, as `?` will trigger an early return.
26. end

28. # The `?` operator may be used in any expression:
29. function run()
30. std.print("div: ", safe_div_mod(5, 0)?.div)
31. end

1 One can actually catch a panic using the std.catch function, but that should be used sparingly.

2 If you’re familiar with both languages, Hush‘s try operator might feel like the unholy child of Rust’s ? operator and Go’s if err != nil { return err }.