Right now, you can do this
enum Foo {
One(u8),
Two(u8),
Three
}
use Foo::*;
fn main () {
let x = One(42);
match x {
One(n) | Two(n) => {
println!("Got one or two with val: {}", n);
}
_ => {}
}
}
but not this
enum Foo {
One(u8),
Two(u8),
Three
}
use Foo::*;
fn main () {
let x = One(42);
if let One(n) | Two(n) = x {
println!("Got one or two with val: {}", n);
}
}
The same goes for pattern guards.
The RFC for if-let proposes the if-let notation pretty much as syntactic sugar for a match block with an empty arm at the end. However, if-let doesn't allow matching on pattern guards and multiple patterns. Extending the if-let notation to allow guards and multiple patterns feel like a natural extension to the current functionality with plenty of use cases.
I've started on an actual rfc, but there might be some parsing and syntactic details we'd have to figure out before it makes sense to finish it. For instance, if let Some(n) = x if n = 0 looks weird at best.
On the positive side, adding support for guards and multiple patterns shouldn't break anything.
cc @Manishearth
Actually this relates to another issue: Why don't we allow alternations (|) in _any_ patterns, not just top-level patterns in match?
@lifthrasiir It certainly does, but I feel like many of the issues that pertain to #99 don't apply here, since if-let is really just sugaring for a match statement.
I guess the only changes we need here are to allow | in the grammar and extend if let parsing to produce ExprMatches with multiple Pats per arm. No change to the AST required (yay).
My bad, we'll need to make ExprIfLet take a Vec<Pat>
This branch adds support for multiple patterns in both if-let and while-let statements. If we want to do the same for guards, we'll probably need to discuss what syntax we want.
https://github.com/Munksgaard/rust/tree/if-while-let-multiple-patterns
I don't think if let should support guards. if let Some(a) == bar && baz() {} seems like a reasonable syntax however. But I'm wary of supercharging if let, it's just a sugar after all.
I don't really see any other reasons beside the syntax for not letting if let support guards. As you said, it's just sugar, so any guards would translate directly into a match guard.
As you're saying though, the syntax could get really ugly.
Wouldn't if let Some(a) == bar && baz() {} introduce ambiguity? For instance: if let true = x && false { }
Yep. Another reason to avoid it :)
I've wanted guards in if let multiple times. This is an easy backwards compatible change. +1 from me.
For some reason while let ... if ... { ... } strikes me as a little brain-twisting at first, but the semantics are clear.
@pcwalton:
Yeah, I'm mostly for that syntax as well, no ambiguities, even though it's a bit of an eyesore.
https://github.com/rust-lang/rfcs/issues/929 is similar to this bug but it focuses on on adding && instead of |. It uses || because of similarity to if A || B although it was only minor because I thought || might be more unlikely to be accepted.
My last comment was a mistake. They do look slightly similar but they are completely different types of proposals.
What is the status of this, and is this the latest discussion?
I want to talk about this as someone who is new to Rust but has significant experience with C++ and has played with Haskell. Rust sold itself to me before I had even written a line.
I read about patterns in the book. Then I read about if let in the book, and it doesn't mention any restrictions. As someone coming into the language, this feels like a bug or oversight, not something that should have an RFC.
I do agree that the syntax is ugly, but I don't see it as any less ugly than the corresponding match for the same thing. The if let has the pattern guard, but the match has the second arm, the pattern guard, and an additional level of nesting.
If there is some obvious reason that this shouldn't work as one would expect, I'd love to know what it is. A lot of my annoyance with learning Rust has been mitigated because I can look at it and see the obvious reason. But I can't here, and it doesn't exist judging by the other comments on this issue. I would expect that a pattern is always the same thing and following the same rules, not that it's sometimes different.
I just run into this, was surprised I couldn't use a guard in the if-let.
This looks very weird and wouldn't have expected it to compile:
if let <pattern> = .. if x > 3 { /* ... */ }
But I was expecting the following to work: if let ... && <cond> { /* ... */ }
I've run into this several times as well. Can't we just have a single syntax for a "pattern" which includes multiple cases, guards, etc. and is used for match, if let and while let. This adds a useful feature while also simplifying the language.
That sort of pat does not make sense in the context of arguments (e.g. fn
peach(a if a > 0: i32), though.
On Aug 28, 2016 9:36 PM, "Diggory Blake" [email protected] wrote:
I've run into this several times as well. Can't we just have a single
syntax for a "pattern" which includes multiple cases, guards, etc. and is
used for match, if let and while let. This adds a useful feature while
also simplifying the language.—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/rust-lang/rfcs/issues/935#issuecomment-242991274, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AApc0r1dlgpwIJAQEI9ZgxGqK4HNB4hFks5qkdU0gaJpZM4DpR5H
.
@nagisa That's simply the difference between refutable and irrefutable patterns. Function args must of course be irrefutable, unless you allow multiple function definitions to cover all possible cases.
I the merged RFC #2175 covers this issue; so I'm closing it.
the merged RFC #2175 covers this issue
But if let with guard is not covered...
I have wanted this feature many times, it doesn't make sense for it to not be there.
I don't understand why this was closed — there are more things missing from if let than just or-patterns. Can we re-open? Or does if let support all pattern features now?
@Twey issues on the rfcs repo aren't really a "thing" either way, they're used inconsistently and we're moving away from that. Feel free to discuss this on internals.rust-lang.org and open an RFC
Most helpful comment
What is the status of this, and is this the latest discussion?
I want to talk about this as someone who is new to Rust but has significant experience with C++ and has played with Haskell. Rust sold itself to me before I had even written a line.
I read about patterns in the book. Then I read about if let in the book, and it doesn't mention any restrictions. As someone coming into the language, this feels like a bug or oversight, not something that should have an RFC.
I do agree that the syntax is ugly, but I don't see it as any less ugly than the corresponding match for the same thing. The if let has the pattern guard, but the match has the second arm, the pattern guard, and an additional level of nesting.
If there is some obvious reason that this shouldn't work as one would expect, I'd love to know what it is. A lot of my annoyance with learning Rust has been mitigated because I can look at it and see the obvious reason. But I can't here, and it doesn't exist judging by the other comments on this issue. I would expect that a pattern is always the same thing and following the same rules, not that it's sometimes different.