Pre-RFC: flexible `try fn`

Centril's master plan for error handling:

Here is my current (so it's subject to change...) master plan for error handling in Rust:

  1. We have try fn and lint in clippy in favor of it over fn .. -> Result<..>.

    EDIT: Addenda to "lint in clippy":

    @scottmcm and @rpjohnst have convinced me that linting in clippy uniformly in this way would be too agressive and that it would not be consistent / uniform with async fn which we would not lint for in this way since you can't always move towards async fn. Sometimes, you might also want to lint towards fn... instead of towards try fn depending on the usage.

    As @scottmcm pointed out, we might want a more subtle:

    "you used ? and Ok( 7 times each, but literally never mention Err(; have you considered try?"

    Therefore, I'm retracting my support for such an aggressive clippy lint.

  2. try and try fn do Ok-wrapping in the tail position.

    try fn foo() -> Result<usize, ()>  { 1 }
    try { a? + b? }
    
  3. fail does Err-wrapping everywhere (fn, try fn, try, ..).

    try fn bar() -> Result<(), usize> { fail 1; }
    fn bar() -> Result<(), usize> { fail 1; }
    try { fail 1 }
    
  4. break is permitted at the top level of a function.

    This means that the following becomes legal:

    fn foo() -> usize { break 1; }
    

    Effectively, break becomes the "return to the closest scope that is a stop-gap (try, fn, loop, while, for)"

    This change makes transitioning from a try block to a try fn easier.

  5. break does Ok-wrapping inside try fn and try.

    try fn foo() -> Result<usize, ()> { break 1; }
    try { break 1; }
    
  6. return does Ok-wrapping inside try fn.

    try fn foo() -> Result<usize, ()> { return 1; }
    
  7. there is no pass / you shall not pass.

    I (think) originated the idea, but I'd like to take it back... I don't like the idea anymore.

    Why? Because it does not fit in the imperative-monadic framework of return being a sort of pure with early-return. Adding another keyword seems wasteful and creates problems for Ok-wrapping in the tail position.

  8. Optional point: adding automatic labels such as 'try.

    To enable easy disambiguation between break to loop { .. } and to try { .. }, you can use the automatic label 'try with break 'try expr. These automatic labels can be added for 'try, 'if, 'while, 'for, 'loop, 'fn, 'match, allowing users to build powerful macros if they wish using label-break-value.

While this system is not 100% consistent, it is as close as I got.

7 Likes