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
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
flecha check curriculum/main-evidence/single/error_values.flflecha build curriculum/main-evidence/single/error_values.fl -o build/error_valuesbuild/error_valuesExpected output
42exit status: 0Related reference: /examples/error_values/.