Skip to content

3. Errors and tests

Expected failures are values. Define an error family, return it beside any success value, and inspect it before consuming the result. Reserve crashable operations for contexts where termination is the declared policy; do not hide ordinary I/O, parsing, or allocation failure.

Tests live in paired _test.fl modules and receive a testing::UnitTest. Arrange inputs, call the exported behavior, and assert on both the result and its error. longbow test compiles the same module graph as the application and returns nonzero when any test fails.

Use error values for the value model, crashable functions for the explicit termination boundary, and testing for assertions and runner behavior.

Tested example

Make division failure explicit, widen a named error deliberately, and print only the successful result.

File: curriculum/main-evidence/single/error_values.fl

curriculum/main-evidence/single/error_values.fl
error MathError {
DivisionByZero,
Overflow,
}
error ParseIssue {
InvalidDigit,
}
(i32, MathError) divide(i32 numerator, i32 denominator) {
if denominator == 0 {
return (0, MathError.DivisionByZero);
}
return (numerator / denominator, none);
}
// A named error widens to error, including inside returned tuples.
(i32, error) calculate(i32 numerator, i32 denominator) {
return divide(numerator, denominator);
}
i32 main() {
quotient, err := divide(84, 2);
if err != none { return 1; }
i32 unused, error failure = calculate(1, 0);
if failure != MathError.DivisionByZero { return 2; }
// One generic variable can hold failures from different families.
failure = ParseIssue.InvalidDigit;
if failure == MathError.DivisionByZero { return 3; }
// Success is explicit; uninitialized error variables cannot be read.
MathError success = none;
failure = success;
if failure != none { return 4; }
const MathError fixed = MathError.Overflow;
MathError first, second = (fixed, success);
if first != MathError.Overflow or second != none { return 5; }
stdoutln(quotient);
return 0;
}

The block above is the complete file executed by the commands below.

Division returns a value and an error separately. The caller tests the error before using the value, so failure stays visible in the function signature and at the call site.

Commands

Commands
flecha check curriculum/main-evidence/single/error_values.fl
flecha build curriculum/main-evidence/single/error_values.fl -o build/error_values
build/error_values

Expected output

Expected output
42
exit status: 0

Related reference: /examples/error_values/.