Errors and checked arithmetic
In AEL, the Agent Engineering Language, arithmetic and indexing have defined results: an overflow or an out-of-range access is reported, never silently ignored. Failures come in three kinds, and AEL keeps them apart.
| Kind | When | What happens |
|---|---|---|
| Diagnostic | You check or build your code. | Nothing runs until you fix the source. |
Result error | An operation fails in a way the program expects, such as a full list or a missing record. | The function returns Result::Err, a typed value you handle like any other. |
| Panic | A defect: an overflow, a division by zero, an index out of range. | The program stops with a failure report. It is never caught as a Result. |
Agents add a fourth kind, a supervised fault, which Concurrency describes.
Returning and handling errors
A function that can fail returns Result<T, E>. The error type E is usually an enum of your own.
enum PriceError {
Negative,
TooMany,
}
fn line_total(price: i64, quantity: i64) -> Result<i64, PriceError> {
if price < 0 {
return Result::Err(PriceError::Negative);
}
if quantity > 1_000 {
return Result::Err(PriceError::TooMany);
}
return Result::Ok(price * quantity);
}
fn total_or_zero(price: i64, quantity: i64) -> i64 {
match line_total(price, quantity) {
Result::Ok(total) => { return total; }
Result::Err(_) => { return 0; }
}
}
- An error is a value. There are no exceptions, nothing is thrown, and nothing is retried unless your code retries it.
- The caller handles the error with
match, or returns its ownResult. - If
price * quantityoverflows, that is a panic, not an error: see below.
Built-in error types
| Type | Variants | Returned when |
|---|---|---|
CapacityError | Full | There is no room left. |
IndexError | OutOfBounds | An index does not exist. |
CastError | OutOfRange | A value does not fit the target integer type. |
StringError | InvalidUtf8, Full | Bytes are not valid UTF-8, or the text does not fit. |
A full collection returns an error and stays exactly as it was: nothing is half-added. When a value cannot be added to a full list, the error gives the value back to you. Results and errors lists which library operations return each type.
Checked arithmetic
The same rules apply to every build, with no difference between a debug build and a release build.
+,-,*and unary-panic when the result does not fit the type./rounds toward zero:-7 / 2is-3.%keeps the sign of the number divided:-7 % 2is-1, anda == (a / b) * b + a % balways holds.- Dividing, or taking a remainder, by zero panics.
- For a signed type, the smallest value divided by
-1panics, and so does its remainder by-1. - Unary
-is for signed types only; on an unsigned value it fails the check.
Shifts and bitwise operators
- The shift count of
<<and>>is an unsigned integer of the same width as the value: ani16shifts by au16. - A count equal to or greater than the width panics.
<<panics when the result does not fit.>>on a signed value rounds down; on an unsigned value it fills with zeros.&,|,^and~work on the exact bits of one integer type, and never onbool.
Explicit alternatives
When you want a different behaviour, you ask for it by name, from the standard library (Numbers lists them):
- Wrapping operations that wrap around the type's range.
- Saturating operations that stop at the type's smallest or largest value.
- Checked conversions between integer types, which return a
Result<T, CastError>that holds an error when the value does not fit. AEL has no conversion that silently cuts bits off.
Indexing
- An index into an array or a list is checked against its length before the access, and an index out of range panics.
- Text has no index operator. Reading one byte of text returns a
Resultwith anIndexError. - A text literal longer than its type allows fails when you check your code, before anything runs.
What a panic does
A panic stops the program at once. On a desktop or server, the program reports what kind of defect stopped it and exits with a failure status. Microcontroller boards describes what a board does after a panic.