?? and ?.
?? and ?. are part of the same user-facing family, but they are not
Result error handlers.
?? is Optional / pointer null coalescing
nullable_expr ?? fallback_expr
Accepted receiver shapes:
| Receiver | On present / non-null | On none / NULL |
|---|---|---|
Optional<T> |
yields wrapped T |
yields fallback |
ptr T |
dereferences and yields T |
yields fallback |
Result<T> ?? fallback is rejected. Use result ? fallback for Result
fallback unwrap.
int32:x = maybe_ptr ?? 0i32;
int32:y = maybe_result ? 0i32;
?. is safe field navigation
receiver?.field
Accepted receiver shapes:
| Receiver | Result |
|---|---|
Optional<Struct> Some |
Some(field) |
Optional<Struct> None |
None |
bare Struct |
Some(field) |
ptr Struct non-null |
Some(field) |
ptr Struct NULL |
None without dereference |
The result of ?. is an Optional field value, which can be combined with
??:
int32:x = maybe_box?.count ?? 0i32;
Result receivers are rejected
?. is not Result error navigation. A Result must be handled first with
?, ?!, defaults, raw, or catch.
int32:x = get_box() ? Box{ count: 0i32 };
int32:n = x.count;
Why this split exists
The v0.33.x decision is intentionally simple:
?,?!,?|,defaults,catch,raw, anddropare Result handling surfaces.??and?.are Optional/null handling surfaces.
That keeps error handling separate from absence/null handling.