Error Handling
Jda provides multiple mechanisms for error handling: the Result type for recoverable errors, defer for cleanup, panic for unrecoverable errors, and the ? operator for error propagation.
Result Type
Functions that can fail return a Result:
struct Result<T> {
tag: i64 // 0 = ok, 1 = err
value: T // the success value
error: i64 // error code
}The ? Operator
The ? operator unwraps a Result — returning the value on success, or propagating the error on failure:
fn read_config(path: &i8) -> Result<Config> {
let fd = file_open(path)? // propagates error if open fails
defer file_close(fd)
let data = file_read_all(fd)? // propagates error if read fails
let config = parse_config(data)? // propagates error if parse fails
ret ok(config)
}Without ?, you’d need explicit error checking at every step:
fn read_config(path: &i8) -> Result<Config> {
let fd_result = file_open(path)
if fd_result.tag == 1 { ret fd_result }
let fd = fd_result.value
// ... and so on for every call
}Defer for Cleanup
defer ensures cleanup code runs regardless of how the function exits — normal return or early error return via ?:
fn process_file(path: &i8) -> Result<i64> {
let fd = file_open(path)?
defer file_close(fd) // always runs
let buf = alloc(4096)
defer free(buf) // always runs
let n = file_read(fd, buf, 4096)?
ret ok(n)
}Multiple defers execute in LIFO order:
fn do_work() {
defer print("3\n")
defer print("2\n")
defer print("1\n")
print("working\n")
}
// Output: working, 1, 2, 3Panic
For unrecoverable errors, use panic:
fn must_positive(x: i64) -> i64 {
if x <= 0 {
panic("expected positive number")
}
ret x
}panic prints a message to stderr and aborts the program with a non-zero exit code.
Error Handling Patterns
Wrapping Errors
fn load_user(id: i64) -> Result<User> {
let data = db_query(id)?
let user = parse_user(data)?
ret ok(user)
}Default Values
fn get_port() -> i64 {
let result = env_get("PORT")
if result.tag == 1 {
ret 8080 // default
}
ret atoi(result.value)
}Assert for Invariants
import "assert"
fn divide(a: i64, b: i64) -> i64 {
assert(b != 0, "division by zero")
ret a / b
}