 # Option<Result<T, E>> and ? returning a 'Some<Err<E>>'

I have a function with return type `Option<Result<T, E>>` where

1. each function is a 'rule'

2. None = this rule is not relevant, try next rule

3. Some(Ok(..)) = applied rule, got result

4. Some(Err(..)) = applied rule, got error

``````fn foo(...) -> Option<Result<T, E>> {

let x = ... ?; // returns None if it doesn't match.

let y: Result<T2, E> = blah(x);

let z: T2 = y?; // if y is an E, let's return Some(Err(E))
// is this line possible? The best I can think of is:

match y {
Err(e) => return Some(Err(e)),
(Ok(z) => ...
}

// but I don't like this 'solution', as I actually have:

let y1: Result<T2, E> = blah(x);
let y2: Result<T3, E> = foobar(x);
/// ... and more
}
``````

Am I basically forced to create two functions here?

One option could be to write

``````let z: T2 = match y.transpose() {
Err(e) => return Some(Err(e)),
Ok(v) => v,
};
``````

But this would be made much easier if all of your functions returned `Result<Option<T>, E>` rather than `Option<Result<T, E>>`. Is there a reason you chose the latter over the former?

Edit: ahh, I just realized that `Option` being the outer type makes `let x = ... ?` actually work.

I don't know of a way to have niceness for both returning None on None and returning Some(Err) on Some(Err). Would it be at all reasonable to just return a `Result<T, E>` and have your error type contain a variant for "rule not relevant", maybe with some combinator functions for ignoring it?

1 Like

Maybe return `Result<T, Option<E>>`, `Err(None)` means the rule is irrelevant, and `Err(Some(_))` means tried and failed.

3 Likes

I have decided to split this into two functions/layers. After all, these is two layers of logic:

1. do the dynamic types match for this rule to apply ?

2. when we apply this rule, do we get answer or an error ?