"Result" block similar to async block

Recently, I think I understood how async blocks work. Basically, writing inside an async block is like writing in an async function, meaning that you can use .await, and the block returns the impl Future instead of the value it would give if it were a regular block.

Has a similar way of dealing with results been investigated ? It's quite a niche scenario but it happened to me a few times, that I'm in a function that doesn't return a result, but where I still would like to be able to use the ? operator. Something like

fn computation() -> Result<i32, ()> {
    Ok(0)
}

fn add(i: i32, j: i32) -> Result<i32, ()> {
    Ok(i + J)
}

fn main() {
    let r: Result<i32, ()> = result /* a result block */ {
        let i = computation()?;
        let j = compuation()?;
        Ok(add(i, j)?)
    };
    
    match r {
        Ok(r) => println!("The result is {}.", r),
        Err(e) => println!("An error occured"),
    }
}

I know I could probably achieve the same thing with a lambda, but I don't find it very elegant, and for now, my solution is to move all the code to another function that returns a result, and use that function in my other function that checks if it succeeded or failed.

This is the try_blocks feature, which is currently unstable. I don't know if there's any progress on stabilizing it, though.

3 Likes

You can do exactly that with an immediately invoked closure :

let r = || {
    let i = computation()?;
    let j = compuation()?;
    Ok(add(i, j)?)
};
match r() {
     Ok(r) => {},
     Err(e) => {},
}
2 Likes

Thanks for the quick answer. This kind of things just make me love rust even more. This language is so awesome !

One of the blockers for it was resolved last year, with Resolving Ok-wrapping for try blocks (rust#70941).

The other big question right now the fact that it too often needs type hinting. There was a sketch of a potential way forward from that in https://rust-lang.github.io/rfcs/3058-try-trait-v2.html#possibilities-for-try, but only in a non-normative section, so there still needs to be a real proposal with that (or another approach, or an argument that it's not really a problem).

1 Like

The problem with that approach is that closures are not exactly transparent. They can't temporarily move out of bindings that are later used outside the closure and they also borrow more things than they actually need. Still, someone already made a crate with this idea try_block::try_block - Rust

1 Like

Well, given that you need to provide explicit types anyway, you may as well use a separate closure or standalone fn. They result in probably equally many lines of code as a try block, and so it won't make much a difference which one is used (which calls into question why there should be such a thing as a try block in the first place).

That's not a fundamental restriction, though. I'm confident that for simple cases like this

we'll be able to find a way that it'll work fine without needing the manual type annotation.