Error Handling
16.1 Exceptions
Hierarchy: Exception → CatchableError (recoverable: IOError, ValueError, KeyError, OSError...) and Defect (programming bugs: IndexDefect, RangeDefect, NilAccessDefect, AssertionDefect, OverflowDefect, FieldDefect, DivByZeroDefect).
Defects should not be caught. With --panics:on, they abort the program immediately.
type
AppError = object of CatchableError
ValidationError = object of AppError
field: string
proc validateAge(age: int) =
if age < 0:
raise newException(ValidationError, "age must be non-negative")
try:
validateAge(-1)
except ValidationError as e:
echo "Validation: ", e.msg
except IOError, OSError:
echo "IO problem: ", getCurrentExceptionMsg()
except CatchableError:
echo "something else"
else:
echo "no error"
finally:
echo "cleanup"16.2 Raising and Re-raising
try: riskyOp()
except ValueError as e:
log(e.msg)
raise # re-raise the current exception
raise (ref ValueError)(msg: "custom", parent: nil)16.3 defer, try as an Expression
let n = try: parseInt(input) except ValueError: 016.4 Assertions
assert x > 0, "x must be positive" # disabled with -d:danger / --assertions:off
doAssert x > 0 # always checked16.5 Result-Based Error Handling
The results package (from Status) provides Result[T, E] with ? propagation, valueOr, isOk, mapErr:
std/options for optional values. Exceptions vs results is a design choice. Effect tracking (Module 20) makes exceptions explicit.
import results
proc parsePort(s: string): Result[int, string] =
try:
let p = parseInt(s)
if p in 1..65535: ok(p) else: err("out of range")
except ValueError: err("not a number")
proc connect(s: string): Result[void, string] =
let port = ? parsePort(s) # early return on error
echo "connecting to ", port
ok()16.6 Stack Traces
Enabled in debug mode. --stackTrace:on, --lineTrace:on, getStackTrace(), e.getStackTraceEntries().