Let … else if … else

I just had a use case for

let Some(x) = y
else if its_ok {
    break
} else {
    return Err("It's not ok!")
};

But Rust deviated from its rule of else must be followed by a block or if. DuckDuckGo doesn't find anything for "let else if". So, was there no discussion about this obvious feature?

Of course it could be worked around with ugly nesting, but then so could any else if. Though useful for avoiding nesting, let else is already an odd feature. It shouldn't be odder than necessary by introducing an exception for what can follow else!

N.b. this is a more natural extension than Pre-Pre-RFC: `let else match` statement

2 Likes

This reads better to me, but it's clearly a subjective quality:

let x = match y {
    Some(x) => x,
    None if its_ok => break,
    None => return Err("It's not ok!"),
};
12 Likes

A reasonable rationale for why let-else doesn't have let-else-if is a combination of:

  • Because the let introduces a binding into the containing scope, the else clause is required to diverge. Due to this, it's not at the same "level" of control flow like the various conditions of an if-else-if are.
  • Avoiding ambiguity for the human relies on } else always being the else of an if-else, and never a let-else. This would break that property.

My baseline response is that the this could make sense, but is ultimately driven by just a desire to remove syntactic nesting instead of allowing the code to better correspond to the logical control flow structure.

let-else-match isn't exclusively about reducing nesting; the claimed value-add is that the match retains access to the scrutinee on failed a pattern match whereas let-else drops it.

2 Likes

I don't get it, is this explained in any document? Is this a literal early drop?

let Ok(v) = get_result() else{
    //no access to Err here
    return;
}

vs

//hypothetical syntax
let Ok(v) = get_result() else match{
    Err(e) => return e.message
}
2 Likes

I'd be more interested in let ... else let and let ... else let ... else:

let Some(x) = foo() else
let Ok(x) = bar() else
let x = baz();

foo() and bar(), of course, will need to return types with the same output which would also be the return type of baz(), because they'd be bound to the same x.

Not sure about how this should be formatted though...

1 Like

You can do that with rust monadic API: