Using `if let` to check for equality

It's not silly at all, but useful. For example, consider fn foo(Wrap(x): ...) or fn foo((Ok(x) | Err(x): ...).

2 Likes

Yeah, so Rust managed to avoid the usual pitfall of if x = 42, so it shouldn't need Yoda conditions... and yet we still have them. I don't think that's good.

It would probably make sense to continue allowing it for code generation purposes. Suddenly failing to compile Yoda patterns would probably introduce a non-uniformity that would in turn require many macro authors to come up with special cases.

Oh, I didn't suggest we disallow it. We also allow if 42 == x, after all.

I just really dislike it being idiomatic for hand-written code.

4 Likes

I didn't mean the Yoda condition is good -- I was just amused to make the connection. Overall it's a natural edge case for pattern matching though. You can also write a constant let when it's irrefutable, like let () = println!(...);, which is only useful to statically assert the fact that it is constant.

I'm with this guy

I see a lot of questions about more complex syntax and determining scope and whatnot. What if we started by implementing only the minimum-viable syntax (if $expr is $pat {}) and disallow anything more complex at first? This simple form has obvious semantics and would satisfy the 90% use-case right away, and we can worry about how/whether to extend it later.

This was the same approach taken for if let $pat = $expr {}—we deferred dealing with && and other more complex syntax until later

Because that has no significant advantage over matches!().


Note that at this point the thread is very much repeating itself:

So someone with more free time than I currently have (sorry! :sob: ) should probably put up an RFC that spells out the argument: "let's stabilize matches!() since everyone wants it, and no one's been able to come up with a compelling variable bindings story, or any other reason to provide this functionality via a new is keyword". Never mind, I completely missed that this is being stabilized.

1 Like

matches! is already stable in 1.42-beta.

2 Likes

It has no significant advantage in the same way as for-loop has no significant advantage over an explicit loop over an iterator. In other words: yes, it's a sugar construct, but which is significantly easier to type, read and perceive over matches!() ("natural to read" property is quite a nice one). Considering that it covers a sufficient fraction of use-cases, I believe at the very least it's a proposal worth consideration.

Personally I wouldn't be against it, but on my list of "nice to have" features it's quite low.

See:

Bindings are a significant improvement. To put it into code, with is you can do this:

if opt is Some(x) {
    println!("We got ourselves a {}", x);
}

Correct me if I'm wrong, but that's not possible with matches!(). That is the shortcoming we're talking about.

But that can be done with if let

4 Likes

Yes, but now we're back to yoda conditionals.

if let 42 = x {}

I guess this really is going in circles :smile: I'll abstain.

2 Likes

So just use if let with binders and matches! without binders, then?

That seems like a reasonable approach to me, anyway.

1 Like

To my mind the feature that's really missing is let-else:

    let Some(x) = x else {
        return Err(something_complicated(y));
    }
    // x is unwrapped here
    // compile-time error if this point is reachable from the else block

I know this has been discussed before but I don't know what, if any, conclusions were reached and it's hard to search for.

6 Likes

TL;DR obvious syntax is ambiguous (sadly), focus is on if-let chaining currently (positive case), then potentially moving to the negative case. There is a draft that consistently allows "`let as a boolean-evaluated expression".

1 Like

Nitpick: "equals" is how I'd read ==; let ... = ... should be "let ... equal..." (no 's').

1 Like

Ah, true. "if let forty-two equal x"

On topic, I don't really think we need an is operator, since if-let already works for those usecases anyway, and for simple matching (assuming you don't want to use a constant let, since it reads weirdly: if let Some(42) = x), there's matches!(), so I'm not sure is is worth cluttering the syntax with. Unlike with ? and try!(), I don't think this is a really common thing.

1 Like

I'm tempted to use matches as is; --> is!(x, 42)

Heh, is that allowed under current macro import semantics?

is seems confusing to me, given that in Python (and I think some other languages) it refers to referential equality, which is very different from pattern-matching equality.

And, as mentioned above, introducing new bindings is done with let. The only exceptions I can think of are function arguments and globals. It would be good to maintain this consistency.

1 Like