Pass a failure back with ?
Put ? after a Result expression to extract its Ok payload or return its
Err immediately. The example’s main preserves allocation and printing errors
in AllocError | IoError; checked_name keeps its concrete str error.
def validate(name: str) -> Result[(), str]:
if len(name) == 0:
return Err("name is empty")
Ok(())
def checked_name(name: str) -> Result[str, str]:
validate(name)?
Ok(name)
def main() -> Result[(), AllocError | IoError]:
print(str.repr(checked_name("Plenty"))?)?
print(str.repr(checked_name(""))?)?
Ok(())
Result[str, str].Ok("Plenty")
Result[str, str].Err("name is empty")
validate(name)? stops checked_name on failure, skipping Ok(name). Error
propagation cleans up local values and temporaries, just as return does.
str.repr formats a result wrapper so either outcome can be printed.
This example displays both results for inspection; it does not propagate the
validation error out of main. In an application where validation must succeed,
use ? on checked_name and include str in the enclosing function’s error type.
Ordinary print requires a handled result:
print(checked_name("Plenty")?)? prints only the successful name.
An expression statement cannot silently discard a result:
def main() -> Result[(), AllocError | IoError]:
print("hello")
Ok(())
cannot implicitly discard a Result
Propagate with ?, match to recover, or use drop(result) to intentionally
ignore either outcome. The discard check does not cover unused bindings or
Option values.
? works with Option too: it extracts Some or immediately returns Nothing.
def positive(n: i64) -> Option[i64]:
Some(n) if n > 0 else Nothing
def same_positive(n: i64) -> Option[i64]:
Some(positive(n)?)
def main() -> Result[(), IoError]:
print(same_positive(42))?
print(same_positive(-1))?
Ok(())
Option[i64].Some(42)
Option[i64].Nothing
This example passes the positive value through unchanged to isolate optional
propagation. Arithmetic that might overflow needs a Result contract or local
checked recovery;
Option does not silently convert arithmetic failure to absence.
The enclosing function must return the same family: Result for a Result
operand or Option for an Option operand. Success payload types can differ,
but a Result error must either match the declared error type or fit within
its anonymous sum.
For example, Result[(), AllocError | IoError] lets the same function propagate
list allocation failures and printing failures with ?. The sum retains the
original error and adds no allocation. Use match when you want to recover or
translate an error rather than pass it back.
? is not supported inside generators.
def read_number() -> Result[i64, str]:
Err("not a number")
def checked() -> Result[i64, i64]:
Ok(read_number()?)
def main() -> ():
print(checked()).unwrap()
`?` operand error str cannot propagate as i64; the function's error type must include it
Option and Result wrappers do not allocate. Their payloads can:
Some([1, 2]?) allocates the list, with no additional allocation for Some.