Errors & Debugging
Aborting
abort(message) stops the program with an error and a stack trace:
fn first(l: Empty) { abort("first: seq is empty") }
Failed pattern matches – an assignment that doesn't fit, a match with no matching clause, a call with no matching method – abort in the same way.
Optionals and results
For errors you expect to handle, Raven leans on ordinary values rather than exceptions. The standard library defines two small bundles:
bundle Optional { Some(x), Nil() }
bundle Result { Ok(x), Err(e) }
nil is shorthand for Nil(), with nil? and notnil to test and unwrap it – this is what the iteration protocol uses to signal exhaustion. unwrap takes the value out of an Ok, aborting on an Err. Pattern matching handles both cleanly:
match parse(input) {
let Ok(x) { use(x) }
let Err(e) { println(e) }
}
There is no try/catch; failures either abort, or are values you match on.
show and test
The quickest debugging tools are macros. show prints an expression together with its value, and test checks a condition:
> show 2+2
(2 + 2) = 4
> test 2+2 == 4
pass: ((2 + 2) == 4)
Sprinkling test lines through a file is the current idiom for writing tests – run the file and grep for fail.
Stack traces and the debugger
Compiled programs carry debug metadata (DWARF), so aborts come with reasonable stack traces pointing at your .rv source, and you can step through Raven code in a debugger – Chrome DevTools for wasm in the browser, or VS Code's debugger via the editor extension. Pass --strip to raven build to remove the metadata from release binaries.
Compiler development flags
Two flags to know when hunting odd behaviour: --no-inline disables function inlining, and --no-memcheck disables the allocation checks that verify reference counts at exit. Mostly these are for debugging the compiler itself, but they can help isolate a miscompilation – see Contributing.