Error Handling
Kestrel handles "this might be missing" and "this might fail" through two stdlib enums: Optional and Result. There are no null references and no exceptions — every absence and every failure is a value the compiler forces you to acknowledge. (The null literal you'll occasionally see is just sugar for Optional.None.)
Optional vs Result
| Use | When |
|---|---|
Optional[T] | Value might not exist, and "missing" needs no explanation. (lookup, firstOrNil, parse.) |
Result[T, E] | Value might not exist, and the reason matters. (readFile, parseConfig, connect.) |
If you find yourself returning Result[T, ()] because there's no useful error, you wanted Optional[T]. If you find yourself returning Optional[T] and the caller has to guess why, you wanted Result[T, E].
Try Operator
The try operator unwraps a Result. If it's .Ok(value), you get the value. If it's .Err(e), the surrounding function returns that error early.
struct User {
let name: String;
}
enum DbError {
case MissingRow
case BadRow
}
func fetchRow(id: Int) -> Result[String, DbError] {
if id == 1 { .Ok("ada") } else { .Err(.MissingRow) }
}
func parseUser(row: String) -> Result[User, DbError] {
.Ok(User(name: row))
}
func loadUser(id: Int) -> Result[User, DbError] {
let row = try fetchRow(id); // returns early if .Err
let parsed = try parseUser(row); // returns early if .Err
.Ok(parsed)
}
Without try, the same code would have nested match statements three levels deep. With try, the happy path stays linear.
try only works inside a function whose return type is Result-shaped (or compatible). Mixing it with Optional requires an explicit conversion — usually a match or a stdlib helper.
Optional Promotion
When the expected type is Optional[T], a value of type T is automatically promoted to Optional.Some(value):
func cached(key: String) -> Optional[String] {
"hello" // promoted to .Some("hello") — no need to write it explicitly
}
This is a small affordance that keeps Optional-returning functions readable. It only happens at return position and other sites where the target type is unambiguously Optional.