Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign uppropose if let guard #2294
Conversation
Centril
added
the
T-lang
label
Jan 16, 2018
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
(For reference: in Haskell 2010, this same feature is called "pattern guards".) |
This comment has been minimized.
This comment has been minimized.
|
Just going by the examples in the RFC, I find it very difficult to tell where the match block, match arms, guards, etc all start and end (without stopping to consciously reason about it, which imo you shouldn't have to do for "basic" syntax like let/match/if/else). I think that's because these if let guards are significantly longer than everything else in the match block, and maybe that's not representative of whatever "real world usage" of this feature would be like, but it does give me a very strong first impression that this is feature is "going too far" and code would only very rarely be improved by it. @strake do you have any (presumably longer) code samples where the this feature would enable a clear improvement? |
This comment has been minimized.
This comment has been minimized.
leodasvacas
commented
Jan 17, 2018
|
This would close #2214 which is exactly this feature request. It's a natural extension to |
This comment has been minimized.
This comment has been minimized.
I don't see any way to desugar it into existing Rust constructions (at AST/HIR level), unfortunately. (First, every non-pattern condition if expr1 is pat1(bindings1) && ... && exprN is patN(bindingsN) {
stmts1
} else {
stmts2
}=> match expr1 {
pat1(bindings1) => {
if expr2 is pat2(bindings2) && ... && exprN is patN(bindingsN) {
stmts1
} else {
goto ELSE
}
}
_ => goto ELSE
}
goto END:
ELSE:
stmts2
END:In this case For condition chains in "guard" match expr {
pat if expr1 is pat1(bindings1) && ... && exprN is patN(bindingsN) => {
stmts
}
_ => {}
}=> match expr {
pat => match expr1 {
pat1(bindings1) => {
if expr2 is pat2(bindings2) && ... && exprN is patN(bindingsN) {
stmts
} else {
goto NEXT_ARM
}
}
_ => goto NEXT_ARM
}
NEXT_ARM:
_ => {}
}In this case we can't do it in existing Rust because we cannot attach labels to |
This comment has been minimized.
This comment has been minimized.
|
I wonder if labeled I can imagine them being potentially useful in the "common tail" situation for example: 'end: match expr {
pat1 => {
stmts1;
break 'common
}
pat2 => {
stmts2;
break 'common
}
pat3 => {
stmts3;
// no common
}
_ => break 'end,
'common: _ => {
common_stmts
}
}or with complex arm conditions match expr {
pat1 => {
complex_stmts;
if complex_condition {
// It was a mistake to go into this arm after all, let's try something else
break: 'next
}
}
'next: pat2 => {}
_ => {}
} |
petrochenkov
referenced this pull request
Jan 20, 2018
Closed
Allow evaluation and pattern matching within guards (what Haskell calls "pattern guards") #680
This comment has been minimized.
This comment has been minimized.
|
cc #680 |
This comment has been minimized.
This comment has been minimized.
|
@Ixrec i have been writing code to avoid needing this feature, so i have none ready, but could try to write one. @petrochenkov on desugaring: my thought was we could rewrite an match x {
A(a) if let Some(y) = f_a(a) => g(y),
B(b) => f_b(b),
C(c) => f_c(c),
}vs match x {
A(a) => if let Some(y) = f_a(a) { g(y) } else match A(a) {
B(b) => f_b(b),
C(c) => f_c(c),
},
B(b) => f_b(b),
C(c) => f_c(c),
} |
This comment has been minimized.
This comment has been minimized.
|
@Ixrec I made another example; is it better? |
senden9
reviewed
Feb 13, 2018
| # Motivation | ||
| [motivation]: #motivation | ||
|
|
||
| This feature would greatly simplify some logic where we must match a pattern iff some value computed from the `match`-bound values has a certain form, where said value may be costly or impossible (due to affine semantics) to recompute in the match arm. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Centril
Feb 13, 2018
•
Contributor
iff means if and only if to distinguish between logical implication p -> q or logical equivalence p <-> q (which is equivalent to p -> q && q -> p). Could be written out to make it clearer for those not familiar with this particular mathematical jargon.
aturon
self-assigned this
Mar 15, 2018
This comment has been minimized.
This comment has been minimized.
|
The Lang Team discussed this RFC today, with the following take-aways:
Overall, the consensus was that we should move forward with this RFC, but with a clearly provisional flavor (as with other recent syntactic additions): when it comes time to stabilize, we want to take a holistic look at the way the syntax is evolving across these RFCs. @rfcbot fcp merge |
rfcbot
added
the
proposed-final-comment-period
label
Mar 15, 2018
This comment has been minimized.
This comment has been minimized.
rfcbot
commented
Mar 15, 2018
•
|
Team member @aturon has proposed to merge this. The next step is review by the rest of the tagged teams: Concerns:
Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
This comment has been minimized.
This comment has been minimized.
|
I have 2 concerns:
match x {
'C' if let &[n] = parms =>
self.screen.move_x( n as _), // note the linebreak!
...
}or if the bit before match ui.wait_event() {
KeyPress(mod_, key, datum)
if let Some(action) = intercept(mod_, key) => act(action, datum),
ev => accept!(ev),
}
if let A(x) = foo()
if let B(y) = bar()
if cond(x, y) {
...
}This ^ particular syntax was not (iirc) very intelligible in the survey done at #2260. The RFC does write that you can't chain |
This comment has been minimized.
This comment has been minimized.
|
@Centril What consistency between |
This comment has been minimized.
This comment has been minimized.
|
@strake you would not be permitted to chain an |
This comment has been minimized.
This comment has been minimized.
|
I see a majority of boxes checked — what is holding back FCP? |
This comment has been minimized.
This comment has been minimized.
|
@rfcbot concern borrowck We are currently working through how to rationalize our existing patterns in MIR borrowck, and in particular addressing a number of soundness complications. It's not entirely obvious to me how this RFC is going to interact with that -- for example, the current treatment that we are moving towards is that -- in a guard expression -- the bindings from the pattern are compiled into refrences into the value being matched, with an implicit deref. So e.g. in a match like this: match foo {
Some(x) if x > 5 => {..}
}although the type of I feel like before we accept this RFC, we ought to talk through what its MIR desugaring will be and how it will interact with the borrow check. (cc @pnkfelix) |
scottmcm
added
the
I-nominated
label
May 15, 2018
Centril
removed
the
I-nominated
label
May 17, 2018
aturon
assigned
pnkfelix
and unassigned
aturon
May 17, 2018
This comment has been minimized.
This comment has been minimized.
|
@nikomatsakis and @pnkfelix need to discuss more. But the executive summary is: @pnkfelix currently believes that there is a relatively straight-forward semantics under the It might be a good idea to try to work through those semantics, perhaps via a series of examples, within this RFC text. Or it might be a good idea to just accept this RFC, with the understanding that we will need to work out the exact semantics (in terms of when the various bindings occur in the MIR desugaring) as part of the implementation effort. |
This comment has been minimized.
This comment has been minimized.
|
@rfcbot resolve borrowck OK, so it seems I killed the conversation with my comment. I apologize that the comment didn't make it particularly clearly what sort of follow-up would satisfy me. After some consideration, I've decided to withdraw my concern. It's not that I'm not still worried, it's that I think it's ok to merge this RFC basically as our "stated intention" to specify this more clearly. |
rfcbot
added
proposed-final-comment-period
disposition-merge
labels
May 17, 2018
This comment has been minimized.
This comment has been minimized.
rfcbot
commented
May 17, 2018
|
|
rfcbot
added
final-comment-period
and removed
proposed-final-comment-period
labels
May 17, 2018
This comment has been minimized.
This comment has been minimized.
anirudhb
commented
May 26, 2018
|
I think that this sounds good: match keyinfo {
/* Separate 'if let' with 'if' using '&&'
note: && is parsed regularly after initial && separator */
Some(keyinfo) if let Some(key) = get_key(keyinfo) && key == K_ENTER && key == K_UP || key == K_DOWN => {
// stuff
},
_ => {
// other stuff
}
} |
rfcbot
added
the
finished-final-comment-period
label
May 27, 2018
This comment has been minimized.
This comment has been minimized.
rfcbot
commented
May 27, 2018
|
The final comment period, with a disposition to merge, as per the review above, is now complete. |
rfcbot
removed
the
final-comment-period
label
May 27, 2018
Centril
referenced this pull request
May 27, 2018
Open
Tracking issue for RFC 2294, "if let guard" #51114
Centril
merged commit e518d9d
into
rust-lang:master
May 27, 2018
This comment has been minimized.
This comment has been minimized.
|
Huzzah! This RFC is merged. Tracking issue: rust-lang/rust#51114 |
strake commentedJan 16, 2018
•
edited by Centril
Rendered
Tracking issue
I find myself wanting this often (the latest use case being parsing terminal escape codes).