(EDIT: just realized I went way astray from the original bikeshed topic - sorry about that, and feel free to stop me now. Perhaps there’s another thread I should read more about the decisions around catch.)
It seems misleading to make “catch blocks” and “throwing fns” look very similar. It seems to me like they are really separate, orthogonal-ish ideas that can exist separately (if I’m understanding correctly):
- “catch block”: short circuits if a
? fails; final expression in the block is implicitly Ok; return returns from the function, and is still Result.
- “throwing fn”: changes both final expression and
returns to be implicitly Ok.
-
throw: throw 4; would be equivalent to Err(4)?; (could be used in either normal fn or throwing fn).
(Although catch block and throwing fn are so similar that it might be bad to have both of these slightly different concepts.)
“catch block”:
type R = Result<i32, u8>;
fn f1(a: R, b: R, c: R) -> R {
Ok(catch { a? + b? }.unwrap_or(0) + c?)
}
// is equivalent to:
fn f2(a: R, b: R, c: R) -> R {
Ok(match (a, b) { (Ok(a), Ok(b)) => a + b, _ => 0 } + c?)
}
// catch as the outermost block of a function:
fn h1(a: R, b: R) -> R { catch {
let ab = a? + b?;
if ab == 0 { Err(0)?; }
if ab == 1 { return Ok(1); } // No implicit `Ok`.
ab // Implicit `Ok`.
} }
// is equivalent to:
fn h2(a: R, b: R) -> R {
let ab = a? + b?;
if ab == 0 { Err(0)?; }
if ab == 1 { return Ok(1); }
Ok(ab) // Just adds the `Ok` here.
}
“throwing fn”:
fn g1(a: R, b: R, c: R) -> R throws { // or whatever
let ab = a? + b?;
if ab == 0 { Err(0)?; } // (Could also be `throw`.)
if ab == 1 { return 1; } // Implicit `Ok`.
ab + c? // Implicit `Ok`.
}
// is equivalent to:
fn g2(a: R, b: R, c: R) -> R {
let ab = a? + b?;
if ab == 0 { Err(0)?; } // or `return Err(0);`
if ab == 1 { return Ok(1); } // Adds Ok here.
Ok(ab + c?) // Adds Ok here.
}
To avoid that confusing tiny difference, perhaps catch {} blocks should be avoided in favor of something that looks and behaves more like the IIFE (immediately-invoked function expression) in this currently-valid Rust:
fn f3(a: R, b: R, c: R) -> R {
Ok((|| -> R {
Ok(a? + b?)
})().unwrap_or(0) + c?)
}