Skip to content

Option and Result

Vow has no null. Absence is Option<T>; fallible work is Result<T, E>.

fn unwrap_or(opt: Option<int>, fallback: int) -> int {
return opt ?? fallback
}
fn main(caps: Caps) -> int {
let none_i: Option<int> = None
let d = none_i ?? 99
print("opt=", unwrap_or(Some(42), 0), d)
return unwrap_or(Some(42), 0) + d
}
Sugar Role
a ?? b Use b when a is None
opt?.method() Call only if Some; else None
fn read_len(path: String) -> int needs FsRead {
return match read_file(path) {
Ok(s) => len(s),
Err(_) => 0 - 1
}
}
// fragment-only
fn fallible(flag: bool) -> Result<int, int> {
if flag { return Ok(42) }
return Err(9)
}
fn main(caps: Caps) -> int {
let ok_val = try fallible(true) catch (e) { e }
try {
let x = fallible(false)
} catch (e) {
print("caught err=", e)
assert e == 9
}
return ok_val
}

Caps fields are Option<Cap> — no grant means None.

Use case: grants in main — match caps.net

Section titled “Use case: grants in main — match caps.net”

Every field on Caps is an Option. You branch on whether the operator passed a matching --grant flag:

fn main(caps: Caps) -> int {
let a = app.get(app.app(), "/health", health)
return match caps.net {
Some(cap) => serve.listen(a, cap, 8787),
None => 0 - 1,
}
}
  • Some(cap)--grant net: was passed; cap is the live Net handle for serve.listen or net_get
  • None — no network grant; do not call functions that needs Net

This is not try/catch. Some / None describe whether a permission exists, not whether an operation threw an exception. For I/O failures use Result (Ok / Err) or try/catch sugar over Result.

The agent demo on the landing page uses the same pattern for caps.fs_read, caps.net, and caps.env.

Discarding a Result is a type error:

Terminal window
vow check tests/lang/ignored_result.vow --json

Propagate Err to the caller when the enclosing function returns Result. Prefer match or try/catch when you want an explicit local arm.