Style: unwrap_or_else vs ok_or_else

Here is a minor stylistic question: which of the following would you prefer, calling unwrap_or_else:

fn foo() -> Result<Bar, E> {
    let x: Option<Bar> = bar();
    let y = x.unwrap_or_else(|| return Err(ErrOther::new(..).into()) );
    /* use y */
}

or ok_or_else and unwrapping using the ? operator:

fn foo() -> Result<Bar, E> {
    let x: Option<Bar> = bar();
    let y = x.ok_or_else(|| ErrOther::new(..))?;
    /* use y */
}

Written as such, the first option is more boilerplaty and could also require a conversion between error types. Syntactically, I'm really interested in the more pretty version using anyhow macros:

fn foo() -> anyhow::Result<Bar> {
    let x: Option<Bar> = bar();
    let y = x.unwrap_or_else(|| bail!(..));
    /* use y */
}

// VS

fn foo() -> anyhow::Result<Bar> {
    let x: Option<Bar> = bar();
    let y = x.ok_or_else(|| anyhow!(..))?;
    /* use y */
}

Not that it matters much, but I wonder whether you would prefer one version over the other if you had to read really many unwraps.

The first one is probably more confusing, since it might first look like the bail! returns from the outer function, not from the closure.

2 Likes

The first version won't actually compile because it will always return from the closure with the wrong type.

2 Likes

The unwrap_or_else method is for handling None by using a default value. The ok_or_else is for turning None into an error. Thus, if you want to turn None into an error, use ok_or_else.

2 Likes

Eventually, we might also get the alternatives

let Some(y) = x else { return Err(ErrOther::new(..).into()) };

and

let Some(y) = x else { Err(ErrOther::new(..))? };

Rust Playground

1 Like

For anyhow, there’s also the [with_]context methods, so e.g.

let y = x.with_context(|| …)?;

Woops, indeed it does. Guess that closes the question. I got so used to panic in unwrap_or_else that I forgot closures can't return from enclosing functions.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.