← Back to AILP Home

Result — Mandatory Error Handling

Overview

Every function in Nitpick returns Result<T> (except extern functions). The compiler forces you to handle the result — unhandled Results are compile errors. This is the core of Nitpick's safety model at the function level.

Canonical v0.33.6 handling guide: see guide/result/ for the full operator and catch cookbook.

Structure

Result<T> = { T:value, ptr:error, i8:is_error }

Source-facing .error / contextual catch error bindings currently expose the runtime error code as int32.

Creating Results

Inside functions (not main or failsafe):

func:divide = flt64(int32:a, int32:b) {
    if (b == 0) {
        fail 1;              // return error Result
    }
    pass (a / b);            // return success Result
};

Handling Results

// Safe unwrap with fallback
flt64:val = divide(10, 3) ? 0.0;

// Null coalesce is for Optional/pointers, not Result errors
flt64:val = optional_value ?? default_value;

// Emphatic Result fallback unwrap
flt64:val = divide(10, 3) ?! 0.0;

// Defaults keyword — scoped fallback for chains
flt64:val = a() + b() + c() defaults 0.0;
// Shorthand: flt64:val = a() + b() + c() ?| 0.0;

// Drop (discard result entirely)
drop divide(10, 3);
// Shorthand: _? divide(10, 3);

// Raw (extract value, ignore error)
flt64:val = raw divide(10, 3);
// Shorthand: flt64:val = _! divide(10, 3);

// Error-aware fallback
flt64:val = divide(10, 0) catch (err) { 0.0 };

// Discard assignment
_ = divide(10, 3);

Operator Summary

Operator Keyword Meaning
? Safe unwrap with fallback value
?? Optional/pointer null coalesce
?! Emphatic Result fallback unwrap
?\| defaults Scoped fallback for expression chains
_? drop Discard Result entirely
_! raw Extract value, bypass error checking
contextual catch Error-aware Result fallback

raw vs nodropraw is a Result-system unwrap (Result<T>T). nodrop is a RAII-system opt-out (v0.31.6.x, W-04) that suppresses the auto-drop the IR generator inserts for managed regions. They are orthogonal and compose; see guide/drop/surface.md.

Auto-Unwrap in Argument Position

When passing a Result as an argument to a function expecting T, it auto-unwraps:

func:add = int32(int32:a, int32:b) { pass (a + b); };
func:get_val = int32() { pass 42; };

// get_val() returns Result<int32>, but add() expects int32
// Result auto-unwraps in argument position
int32:sum = raw add(get_val(), get_val());

This does not apply to variable assignment — you must explicitly unwrap.

The ok Keyword

ok allows passing a variable whose value may be unknown:

ok maybe_unknown_value;

main and failsafe

main and failsafe are special — they use exit instead of pass/fail:

func:main = int32() {
    exit 0;   // exit program with code 0
};

func:failsafe = int32(tbb32:err) {
    exit 1;   // must exit with code > 0
};

Related