Error handling
XS uses try/catch for recoverable errors and panic for unrecoverable ones. defer runs cleanup code regardless of how a function exits.
try / catch / finally
You can throw any value: strings, numbers, maps, structs. The caught value is whatever was thrown.
Exceptions propagate up the call stack until caught. Nest try/catch to rethrow with context:
throw
panic
panic terminates the process immediately. It prints to stderr and exits with code 1. It is not catchable by try/catch.
panic("fatal: invariant violated")
-- xs: panic: fatal: invariant violatedRelated: todo(msg?) panics with "not implemented" and unreachable() panics if somehow reached. Both signal programmer intent rather than runtime conditions.
defer
defer schedules a block to run when the enclosing function returns. Multiple defers execute in LIFO order. Defers run even if an exception is thrown.
When to use which
throw / catch for recoverable errors: bad input, missing resources, validation failures. The caller can handle them and continue.
panic for invariant violations: states that should never occur if the program is correct. There is nothing sensible to do except crash and report.
defer for cleanup that must happen regardless of success or failure: closing files, releasing locks, logging completion.