Guide
Results
Failure is a returned value rather than an exception, and ? is how it travels.
Failure is a returned value rather than an exception. That matches the rule the host engine already runs on, which is to fail fast at initialisation and never throw inside the frame loop, and a Result in a per-tick path is that rule expressed as a type.
Ok and Err
A function that can fail says so in its return type. The caller either handles both cases or propagates, and there is no third path where the error is quietly dropped.
// Failure is a value, and absence is a type.
//
// `load` cannot throw. Its caller either handles both cases or propagates with `?`, and the
// compiler is what makes that a choice rather than an oversight.
enum LoadError {
Missing
Corrupt
}
data Resource {
size: f32 = 0
}
fn load(present: bool) -> Result<Resource, LoadError> {
if present {
return Ok(Resource { size: 1024 })
} else {
return Err(LoadError.Missing)
}
}
// Propagate: on failure this returns the error unchanged, on success it continues with the value.
fn sizeOf(present: bool) -> Result<f32, LoadError> {
let resource = load(present)?
return Ok(resource.size)
}
// Or handle both cases explicitly. There is no third path where the error is ignored.
fn sizeOrZero(present: bool) -> f32 {
return match load(present) {
Ok(resource) => resource.size
Err(problem) => 0
}
}
Propagating with ?
`?` returns the failure to the caller unchanged and continues with the value on success. It is legal only in a function that returns a Result or an option, and the error types must match.
Ok takes its other half from context
`let a = Ok(1)` with nothing to say what the error type is, is an error rather than a guess. The binding's annotation or the function's return type is what completes it.