Option and Result Types: Error Handling

18.1 Concepts

A value of type T or none A value of type T or an error (IError) Result without a value Success or an error

V has no exceptions and no null. Errors are values that must be handled.

18.2 Results (!T)

import os

fn read_config(path string) !string {
	if !os.exists(path) {
		return error('config not found: ${path}')
	}
	return os.read_file(path)!          // `!` propagates the error to the caller
}

fn main() {
	// 1. or block: handle the error (err is available implicitly)
	cfg := read_config('app.conf') or {
		eprintln('Error: ${err}')
		'default config'                 // fallback value (last expression)
	}
	println(cfg)

	// 2. Propagate with `!` (the enclosing fn must return a result type)
	// 3. panic on error
	data := read_config('x') or { panic(err) }
	_ = data

	// 4. if guard
	if c := read_config('app.conf') {
		println(c)
	} else {
		println('failed: ${err}')
	}
}

18.3 Options (?T)

struct User { name string }

fn find_user(id int) ?User {
	if id == 1 { return User{'Ana'} }
	return none
}

fn main() {
	u := find_user(2) or { User{'guest'} }
	println(u.name)
	if user := find_user(1) { println(user.name) }
	name := find_user(1)?.name     // `?` propagation (inside fns returning an option)
	_ = name
}

18.4 Custom Error Types

error('msg'), error_with_code('msg', 42), err.msg(), err.code().

struct NotFoundError {
	Error                      // embed the base Error to implement IError
	resource string
}
fn (e NotFoundError) msg() string { return '${e.resource} not found' }
fn (e NotFoundError) code() int { return 404 }

fn get(resource string) !string {
	return NotFoundError{resource: resource}
}

fn main() {
	get('user') or {
		if err is NotFoundError {
			println('Custom: ${err.msg()} (code ${err.code()})')
		} else {
			println(err)
		}
		return
	}
}

18.5 Option/Result Fields and Variables

struct Settings {
	theme ?string        // option field
}
s := Settings{}
println(s.theme or { 'light' })
mut maybe := ?int(none)
maybe = 5

18.6 Panics and Recovery

panic('msg') aborts with a stack trace (unrecoverable, for bugs).

assert cond, 'message' panics in debug and test builds.

There's no recover mechanism. Design with results instead.

Array index out of bounds and division by zero panic. arr[i] or { } gives safe access.