Skip to content

Error Handling

Try/catch is verbose. An AI agent generating try { ... } catch (e) { ... } pays tokens for boilerplate, and if it forgets the catch block, the error is silently swallowed. ilo makes errors part of the type system - you can’t forget to handle them.

Any function can bail out early with ^:

ilo
div a:n b:n > n -- says it returns a number...
= b 0 ^"divide by zero" -- ...but ^ can throw an error
/ a b -- otherwise divide
Shell
ilo 'div a:n b:n>n;=b 0 ^"divide by zero";/a b' div 10 2
# → 5
ilo 'div a:n b:n>n;=b 0 ^"divide by zero";/a b' div 10 0
# → ^divide by zero

^ exits the function immediately with an error. But there’s a problem: the return type says > n (a number), so any code calling this function expects a number back - it has no way to catch or handle the error. The error just crashes through.

If you want callers to catch and handle errors, use R as the return type. This wraps the result so the caller can inspect it:

Terminal window
R success-type error-type

Read it as: “Result - first type is what you get on success, second is what you get on error”.

For example, R n t breaks down as:

PartMeaning
Rthis is a Result
nsuccess value is a number
terror value is text

Common patterns:

TypeSuccessError
R n tnumbertext message
R t ttexttext message
R _ tnothing (side effect)text message

Inside the function, ~ marks the success path and ^ marks the error path:

ilo
div a:n b:n > R n t
= b 0 ^"divide by zero"
~ / a b

Now callers can match on the result with ?:

ilo
show a:n b:n > t
r = div a b
? r {~v: str v; ^e: e}
  • ~v: - if success, bind the value to v
  • ^e: - if error, bind the error to e
Shell
ilo 'div a:n b:n>R n t;=b 0 ^"divide by zero";~/a b
show a:n b:n>t;r=div a b;?r{~v:str v;^e:e}' show 10 0
# → divide by zero

Matching every Result is tedious. ! auto-unwraps: success continues, error propagates up. The calling function must also return R:

ilo
calc a:n b:n > R n t
v = div! a b
~ * v 2

div! a b = call div, if error return it immediately, if ok bind the value. One character (!) replaces a whole try/catch block.

O T means “maybe a value of type T, maybe nil”:

ilo
f > O n; nil
g > O n; 42
Shell
ilo 'f>O n;nil' f
# → nil
ilo 'f>O n;42' f
# → 42

?? provides a default when a value is nil:

ilo
f x:O n > n; x ?? 0
Shell
ilo 'f x:O n>n;x??0' f 42
# → 42
ilo 'f>O n;nil' f
# → nil

?? chains: a??b??99 returns the first non-nil value, or 99.

When type verification fails, ilo returns compact error codes:

Terminal window
ILO-T004: type mismatch: expected n, got t

One token, not a paragraph. Agents correct faster with less context.