Error Handling
This proposal has been accepted and implemented.
You can use this feature in the latest version of Zirric.
Introduction
This proposal introduces a standard error protocol and a Result union type for failure-aware APIs. It defines the @Error attribute for marking error types and the @AnyResult attribute for marking result unions.
Syntax sugar for working with result values (!., !!, T!) is covered separately in ZE-019 Result and Option Sugar.
Motivation
Zirric currently lacks a canonical way to represent failures. A shared Result model makes error flows explicit and composable. By separating the type definitions from the syntax sugar, this proposal focuses on the foundational types that other proposals and modules can build upon.
Proposed Solution
Introduce three declarations:
@Error— an attribute marking types that represent errors, requiring adebugfunction.@AnyResult— a marker attribute for union types that represent success-or-failure results.Result— the standard result union withOkandErrvariants.
attr Error {
debug(err) -> String
}
attr AnyResult {}
@AnyResult()
union Result {
data Ok {
value
}
@Error(fn(err) { return err.error.debug(err.error) })
data Err {
error: @Error
}
}
Usage
fn readFile(path: String) -> Result {
// returns Ok("contents") or Err(someError)
}
const result = readFile("notes.txt")
switch result {
case Ok(text):
// use text.value
case Err(error):
panic(Error(error).debug(error))
}
Custom error types implement the @Error attribute:
@Error(fn(err) { return "file not found: " + err.path })
data FileNotFound {
path: String
}
Custom result types can be defined for specific domains:
@AnyResult()
union FileResult {
String
FileNotFound
}
Detailed Design
@Error
The @Error attribute marks a type as an error. It requires a debug function that returns a string representation of the error for diagnostics.
@AnyResult
The @AnyResult attribute is a marker applied to union types. It signals that the union represents a result — one variant for success and one (or more) for failure. This attribute is used by ZE-019 to enable syntactic sugar.
Result
The standard Result union has two variants:
Ok { value }— the successful result, wrapping the success value.Err { error: @Error }— the error result. Theerrorfield must satisfy the@Errorattribute.
Err itself is annotated with @Error, delegating its debug to the inner error’s debug function. This means Err values are composable as errors.
panic
A panic function is added for unrecoverable errors:
extern fn panic(message: String) -> Void
panic immediately terminates execution with the given message. It should be used sparingly — Result is preferred for recoverable errors.
Changes to the Standard Library
| Declaration | Kind | Description |
|---|---|---|
Error |
attr |
Marks error types, requires debug(err) -> String |
AnyResult |
attr |
Marker for result union types |
Result |
union |
Standard Ok | Err result type |
Ok |
data |
Success variant with value field |
Err |
data |
Error variant with error: @Error field |
panic |
extern fn |
Terminate execution with error message |
Alternatives Considered
- Exceptions or panics only — do not fit Zirric’s explicit, attribute-driven model.
- Returning
Option— loses error context and diagnostics.Option(ZE-009) is for absence, not failure.
Acknowledgements
- Influenced by Rust’s
Result<T, E>and Swift’sResulttype. - Syntax sugar for result values is defined in ZE-019 Result and Option Sugar.