Bikeshed: A consise verb for the `?` operator

let _: Result<Foo, Bar> = catch {
    foo()?;          // try or bubble?
    fail Bar(0);     // break w/ err-wrapping, replaces throw
    fail Baz(0);    // like `goto handle` w/ handle identified via pattern match.
    pass Foo(0);     // break w/ ok-wrapping
    Foo(0)           // implicit ok-wrapping
}
handle Baz(0) {      // must break with either Ok(Foo) or Err(Bar)
    fail Biz(1);     // break with Err-wrapping
    pass Foo(1);     // break with Ok-wrapping
    Ok(Foo(2))       // return explicit value (no ok-wrapping)
}

And the eval-based example:

let _: Result<Foo, Bar> = eval { // like "evaluation"
    foo()?;         // try operator
    fail Bar(0);    // break w/ err-wrapping, replaces throw
    fail Baz(0);    // like `goto handle` w/ handle identified via pattern match.
    pass Foo(0);    // break w/ ok-wrapping
    Foo(0)          // implicit Ok-wrapping
}
handle Baz(0) {      // must break with either Ok(Foo) or Err(Bar)
    fail Biz(1);     // break with Err-wrapping
    pass Foo(1);     // break with Ok-wrapping
    Ok(Foo(2))       // return explicit value (no ok-wrapping)
}

I believe the handle semantics could be useful in solving the problem RFC 243 points out about match sugar:

There was some concern about potential user confusion about two aspects:

  • catch { } yields a Result<T,E> but catch { } match { } yields just T;
  • catch { } match { } handles all kinds of errors, unlike try/catch in other languages which let you pick and choose.

The handle logic presented above runs on fail, and can pattern match on the type of any fail, but they must return a value consistent with the statement's type (in the above examples, handlers must return Result<Foo, Bar>). The fail and pass shortcuts are still available, but fail handlers don't recurse, so the type returned in fail must have a std::convert::From implementation to the expression's failure type.