Propagating (`?`) `Result` from function that returns `Option<Result>`

I think this is not possible, based on https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.html:

One current restriction is that you cannot use ? for both in the same function, as the return type needs to match the type you use ? on. In the future, this restriction will be lifted.

But to be sure, I'm asking here...

I have a function that returns Option<Result<T, E>>. It is an implementation of Iterator, but that doesn't matter for now. It calls a function that might fail, and thus returns Result<T, E>. Something like:

fn helper() -> Result<T, E> {
    // ...
}

fn next() -> Option<Result<T, E>> {
    helper();
}

Now, I want next() to fail with Some(Err(E)) if helper() returns Err(E). Of course I can do this the long way:

if let Err(e) = helper() {
    return Some(Err(e));
}

But I'd like to do this using the ? operator. But if I do this raw, the compiler complains (obviously):

error[E0277]: `?` couldn't convert the error to `std::option::NoneError`
 --> src/lib.rs:9:13
  |
8 | fn next() -> Option<Result<(), ()>> {
  |              ---------------------- expected `std::option::NoneError` because of this
9 |     helper()?;
  |             ^ the trait `std::convert::From<()>` is not implemented for `std::option::NoneError`
  |
  = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
  = note: required by `std::convert::From::from`
help: consider converting the `Result<T, _>` into an `Option<T>` using `Result::ok`
  |
9 |     helper().ok()?;
  |             ^^^^^

I can use .ok(), but then the error E is discarded:

helper().ok()?; // Err(e) becomes None instead of Some(Err(e))

I can also wrap it with Some(...), but then the ? operator applies to the Some(...) never returns from the function:

Some(helper())?; // The ? operator  sees Some(...) and never returns

I thought about implementing std::ops::Try, but:

  1. Couldn't figure out how to do this properly.
  2. I think it's not possible since it's cross-crate impl.

Is this possible (I'm not afraid of using nightly Rust)?

Thanks in advance.

You can make a helper function which returns Result<Option<T>, E> and .transpose() it into Option<Result<T, E>>.

https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.transpose

https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.transpose

Actually, I don't have to - I can just refactor the helper function to return Option<Result<T, E>>.

But how do I use the ? operator to return in case of an error?

To ? to reutrn on error you need to have Result as the outer type. That's why I've recommended to use .transpose().

1 Like

The problem is that as I already said it's an iterator, and the next()'s function signature is Option<T> (in fact, in the beginning I implemented it like you suggested).

Ok, I'll explain in more detail. You can write another helper function which returns Result<Option<T>, E>, write most logics in it, and within the fn next() call this helper function and .transpose() its result.

2 Likes

Hmm... Cool. Thanks.