-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add 'else match' blocks to if expressions. #1712
Conversation
baz() => do_that() | ||
} else { | ||
do_something(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
with single variant matches if let
is definitely more readable:
enum Bazz {
Baz,
Bak,
}
fn foo() -> bool { unimplemented!() }
fn baz() -> Bazz { unimplemented!() }
fn do_this() -> () { unimplemented!() }
fn do_that() -> () { unimplemented!() }
fn do_something() -> () { unimplemented!() }
fn main() {
if foo() {
do_this();
} else if let Bazz::Baz = baz() {
do_that();
} else {
do_something();
}
}
I am not convinced this is necessary unless more useful optimization can be done against it. It seems pure aesthetic now. |
} | ||
``` | ||
|
||
## Use-cases |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest, in no of these cases I see a clear improvement. In fact, the opposite is true. I find it "uglier".
If I was going to do anything in this regard, it would be to let
Etc. While this has the downside of not getting the compiler to check for you, it also looks good in the case where you need to match patterns against multiple, different values; the one the RFC proposes would require indentation for this idiom. It might be worth expanding the RFC with this, or closing the RFC and making another along these lines, but something like the above seems much more generally useful. |
expression, with one key addition: | ||
|
||
When an arbitrary expression `exp` in `else match <exp>` fails to match any of the cases in the | ||
`else match` block, the next block (if it exists) is run. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am in favor of else match
, but I am really against this! match
should work consistently.
There is an orthogonal proposal to allow match to take else
s at the end, so you don't have to include the catchall branch inside the match intend. But that proposal should apply to all match
statements, not only the else match
ones.
Integrating |
Removed an example, removed "match else"-style functionality, added some clarification, and slight tweaks to the formatting of the grammar.
@camlorn both This RFC somewhat makes sense to me since we allow |
Instead of special-casing |
@glaebhoerl you mean that this RFC should be written to support |
I think there should be a syntactic category of "things that have blocks", and anything in that category should be allowed. So yes those, and also (Not necessarily this RFC. Just stating my preference in general.) |
Personally, for |
I've wanted to propose this for a while. This pattern seems to come up often for me. |
@glaebhoerl I think "having blocks" is just a syntactic category and there is some semantics to this. Basically I think it should make sense as a 'branching' construct. This could make sense for loops if loops ever evaluate to values, and I have to think about |
To be honest, I don't think so. The way I look at it is, what's the core requirement? The core requirement is to avoid the "
This might make some sense for |
@rfcbot fcp merge This is a small bit of syntactic sugar, but it seems harmless enough, and I know that I have found myself wanting it many times. It frequently happens because I have some guards I need to execute all the time, and then I want to do a bunch of matching in the general case. So I propose we merge it. I would start small: just |
Team member @nikomatsakis has proposed to merge this. The next step is review by the rest of the tagged teams: Concerns:
Once these reviewers reach consensus, 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. |
@nikomatsakis how would you feel about allowing match to carry an else, which would be equivalent to a match an_option {
Some(foo) => { ... }
} else {
...
} It could take an if, which would be the same as a guard: match an_option {
Some(foo) => { ... }
} else if a_bool {
...
} else {
...
} I don't feel that this is necessarily good style, but if we're allowing |
I would like to note that this RFC generally has more of the negative feedback than it has of positive. I personally find that a sign that it ought to be moving towards I’m personally fine with this getting merged provided we also investigate (now, as part of accepting this RFC) making things like I very much dislike the idea of |
@glandium I agree that they don't require But I still don't think they allow
For the Mozilla one, for example, I can see no exception or counterexample to the "Always brace controlled statements" rule that would allow Hmm, DXR looks nice. Let's ask it about
but the else doesn't always return OK because that return is inside a for loop over a linked list. So overall, I can't help thinking that generalized |
@scottmcm Thanks for bringing that up, it's definitely something that's worth investigating. Do we know what their reasons are for disallowing it? That is, is there a substantive reason why it should be considered "bad style"? If there are reasons behind it, we should very much take them into consideration. If we don't know of any, though, then it's still an interesting data point, but I think we should make the decision based on substance ("are there any problems this could conceivably cause?") rather than heuristics ("how do other people do it?"). For what it's worth, I suspect the reason for it is that, in guidelines and conventions, because you're solely reliant on people to keep them all in their head, simplicity and clarity are at a premium, and it's preferable to have few blunt, conservative, but easy to remember rules, than nuanced but more flexible ones. Having the compiler check it for you alters the balance between tradeoffs significantly: if the compiler lets you do it, then you're good to go, and you don't have to second-guess yourself nearly as much. Complexity still has a price, of course, but it's considerably less acute. (And at least in terms of how the rules are formulated, I've argued that For what it's also worth, I've personally been using |
If
or
or
or even
into an obnoxious indentation that hides the loop like
If anything, I've no feelings against |
@burdges: In your first and third example: if .. {
foo(0);
} else for i in .. {
foo(i);
...
...
// Imagine some more code here...
...
...
}
//<-- The lack of an ending bracket on this indentation level
// makes me think that the brackets are unbalanced.
// I feel I'd had to go back and count them.
more_code(); |
@rfcbot fcp close Honestly, I feel like this discussion has been kind of going around in circles. It seems clear that people's intuitions differ here. Therefore, I am moving to close this RFC: I think we ought to just leave things as they are for now. The status quo is reasonable and we can consider more extensions in the future. To summarize some of the recent discussion:
Some things that might help a future revision of this topic make progress:
|
Team member @nikomatsakis has proposed to close this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once these reviewers reach consensus, 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. |
While I was in favor of |
I've also been feeling increasingly inclined to close this. None of this seems obvious enough for the learning cost to not outweigh the convenience cost. |
This is a bit frustrating. I've felt like throughout this thread, there has only been one proposal that has had clear support, but people have kept conflating it with other extensions that very few people think are a good idea. This had the effect of muddying the waters, and making it seem like it was a complicated, confusing and ambiguous situation when it really wasn't. So I thought of doing the straw polls to try to restore some clarity to the situation, and it seems to me that this was successful (moreso than I had expected): it's now completely clear that there is, in fact, only one proposal that has any real support. I had hoped that this would have allowed us to refocus discussion around that one proposal, and to stop getting the others mixed up in it. And now the motion is to close, because there are too many different proposals, and the water is too muddy. I... don't see how this makes any sense. The verbiage in @nikomatsakis's comment and my earlier one is remarkably similar: "I feel like this thread has been drifting around in circles"; "I feel like this discussion has been kind of going around in circles". Yes. Maybe now that it's clear that there's only one direction to go in, we could stop going around in circles? |
I'm in favor of closing this for a slightly different set of reasons from Niko.
|
@glaebhoerl I agree with you that there's been only one real contender for a while; that was clear to me even before the straw poll. And I personally would still be happy to land such a feature. But I think @nikomatsakis was despairing of reaching full consensus around the proposal, since many are still opposed, and those on the lang team are a bit ambivalent; meanwhile, this RFC has been a bit of a timesink with pretty minimal benefits if we do land it. So, for me: I'd love to land this, I'm OK with closing it, but I'm ready to reach a decision. |
@aturon @glaebhoerl can one of you clarify what you see as the "one true contender"? Is it extending I could get behind this proposal but I also feel a lot of ambivalence. I am definitely ready to be done talking about it either way. The win seems relatively slim (less, e.g., than |
@nikomatsakis yes, that's the "consensus" proposal. I'm sympathetic to @withoutboats's concerns for sure, but still would be OK trying it. |
Yes, that's the proposal that makes the most sense to me. It applies rules in a consistent manner, where we can just say It "back-generalizes" why |
I was in favor of the I understand the argument that *The most glaring example of this "familiarity sugar" is |
I think that's the strongest counterargument, fwiw. Finally the discussion we should be having. :) I'm not so convinced that allowing only |
@glaebhoerl But the consistency in the languages you cite is between |
Sure, not more consistent, but not less consistent either. 🤷 |
I'm also a bit sad about the circles here and I'm voting to close because I think the effort is far outweighing the potential benefit at this point. FTR I am in favour of And just to go off topic and risk wasting more time and energy, a note on language design philosophy: IMO, consistency is a means to an end, not a goal. If we try to make consistency an overarching goal (without considering practicality) we will end up with a language which is loved by uber-geeks, popular in academia, and abandoned in practice. As with most things there is a delicate trade off to consider. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
Consistency is not for the sake of itself, it's for the principle of least surprise. |
Substance level: I agree this is a very minor thing, there are reasonable arguments both for and against, and in the end it's not going to make much difference either way -- it's obviously not worth wrangling over. Process level: It kind of bothers me from an incentive-compatibility perspective that a proposal can get sidetracked to death and the official response is, "this proposal has been sidetracked to death so we're going to close it". I might've hoped there would be someone with the responsibility to help discussions stay on track. |
@glaebhoerl I don't think I'd characterize this as "this has been sidetracked to death so we're going to close it". I think I'd characterize this as "this has too much pull in too many different directions to conclude that we have a reasonable consensus in favor of the change". It's not clear whether the "consensus" proposal was "else match" or "else keyword" (multiple people described each as the consensus at various times0, and both had substantial pushback. |
The final comment period is now complete. |
I'm going to go ahead and close out this RFC. While there may still be some merit in ideas along these lines, it has proved too difficult to reach a lasting consensus here, and we have bigger fish to fry in the meantime. Thanks @phoenixenero for the RFC! |
How about using for x in 0..10 => for y in 0..10 {
println!("{:?}", (x, y));
} Or simply bring back the people's favorite ;) |
I don't know if one is allowed to post more comments now that this is closed, but I just wanted to chime in on the discussion: I followed the same path of reasoning for my toy language and eventually settled on two types of statements: action statements and flow control statements. This is very similar to what was discussed here but I think the concept of splitting flow control statements (expressions, in Rust's case) into their own category and separating them from blocks is worth emphasizing. For Rust, this would become:
Note how flow control expressions are broken out as By allowing any flow control expression after Not all keywords should be considered flow control expressions (for example I'm very much a beginner when it comes to Rust, so please excuse me if I've missed something important! |
Rendered
A more specific version of my previous proposal.