-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Match ergonomics 2024 #3627
Match ergonomics 2024 #3627
Conversation
Co-authored-by: kennytm <kennytm@gmail.com>
The " |
It could be split off, yes. I mention this in the rationale section, but one of the motivating factors for including it is the "no inherited |
The "no inherited |
It is not. On edition 2024, this example would work without the rule, but errors with it: (I'll edit the RFC to make that more clear) |
I'm not sure why (a version of) "no inherited Really I'm not sure why we would even want to reject it in the first place. There is still a This is exactly the sort of thing that would be good to work out as part of deref patterns. Going back to the comparison with places, the reason you can get a Accepting this example is a different sort of consistency than the "immutability takes precedence" one. Instead, it's "inherited reference type matches skipped reference type." This also brings back the locality that " If we want to defer any decision at all here, I believe we could instead forbid matching |
If there are several skipped reference types with different mutabilities, you have to choose: eg in |
let _: &mut u8 = foo; | ||
``` | ||
|
||
## Edition 2024: `&` and `&mut` can match against inherited references |
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 like it! With this, is there even a reason to keep supporting &mut
in patterns?
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.
Of course, without it we can't get desugar match ergonomics that get mutable references into places: let &mut Struct { ref mut field } = ...
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.
Right, okay. Sounds worthy of a clippy lint for if it's not combined with ref mut
then :)
The innermost one, of course! Why would it be anything else? That's how default binding modes already work, and we're merely exposing that to the user so they can exit the current mode, not trying to reinvent how the mode is entered. |
No it's not! Outer shared + inner mutable results in |
What I'm saying is that it is how initially entering a default binding mode already works. That's why the example The inconsistency we're both talking about is the difference in behavior between "behind an explicit You're proposing we resolve it in favor of the binding mode (essentially letting explicit |
Here's another way of looking at it: if Simple case: let &mut x = &mut 42; // x: i32
let x = &mut 42; // x: &mut i32 Roundabout case: let &[&mut x] = &[&mut 42]; // x: i32
//let &[x] = &[&mut 42]; // ERROR, but…
let &[ref x] = &[&mut 42]; // x: &&mut i32 -> we can get an &mut in the end However: let &[[&mut x]] = &[&mut [42]]; // If we allow this, with x: i32
//let &[[x]] = &[&mut [42]]; // and then remove the &mut… -> ERROR move check, if the default binding mode is to be `ref mut`
// nothing we do will get us &mut i32 in any form |
Indeed, that is a demonstration of the fact that we are limited to a single layer of inherited reference/a single binding mode. If we relaxed that (not that I think this would be useful in practice), you could get a let &[[&mut x]] = &[&mut [42]]; // x: i32
let &[[x]] = &[&mut [42]]; // ERROR move check, unless the pattern equivalent of auto(de)ref coerces &mut i32 -> x: &i32
let &[[ref x]] = &[&mut [42]]; // HYPOTHETICAL: A `ref` binding + an inherited `&mut` -> x: &&mut i32 My proposal is not so much breaking the user's ability to remove a If I understand what you're getting at, your proposal would avoid this edge case by preemptively replacing |
It is semantically impossible to relax that. E.g. let var = Some(0);
if let Some(x) = &&var {
//...
} Here |
Well, that was only a hypothetical to demonstrate a different way of thinking about the limitation Jules pointed out. But I don't think it's entirely impossible to materialize those extra reference layers- we could introduce temporaries for them around the match, it would just be a bit silly, and they would have shortened lifetimes. (Not to mention confusing to be able to layer binding modes like my example.) |
My understanding of @rpjohnst's position is that he thinks we should accept the union of what the two alternatives accept (is, be maximally permissive). |
I'm not proposing that we keep the old behavior of an unusable I'm also not proposing that we be maximally permissive, @Jules-Bertholet. My primary reason for jumping into this thread has always been to make the argument that we not make the " However, as currently specified, the "no This is why the RFC accepts I look at this consequence of "no So in the spirit of describing this in a self-contained way, I am proposing these changes to parts 2-4 of the RFC's reference section:
This last point should behave the same way as the RFC (e.g. |
Many thanks for the clarifications, @rpjohnst and @Jules-Bertholet. I think I have a good grasp of your positions now.
Leaving more design space open for deref patterns is desirable. At the same time, I struggle somewhat to come up with a scenario in which adopting " While I'd like to avoid going too deep into hypotheticals, is there any way you could sketch out the kind of question this might restrict our choices on in the future, @rpjohnst? cc @WaffleLapkin, who was also worried about interactions here.
For my own understanding, is there a "nuclear option" that rejects both of these and allows us to choose one later? Does that mean delaying " |
It's possible to do, we would have to forbid matching against inherited references in the specific situation that the rule affects. It would be confusing and irritating for users, though. Unless there a compelling reason to think we might gain new information in the future to better inform this choice (and I don't see us), delay will not do any good IMO. |
It's looking like deref patterns will introduce some syntax for "deref a scrutinee of any pointer type, and then match on the result." That syntax may or may not be Similarly, if we introduce " Regarding the "nuclear option," we would only need to reject matching on inherited references which are both A) inherited from a
Personally, I don't believe this is important. The language is full of ways to "talk about" something without being able to "get your hands on it," but these are enforced by the borrow checker, rather than by adjusting types ahead of time. Consider that, given When you rely on auto(de)ref to get a To me it seems more in line with the rest of the language to accepting |
The deciding factor is ultimately whether the lang team has considered all of the information it thinks is relevant, or will have time to do so, without either delaying the edition or risking this RFC as part of it.
What about the second part of my question — delaying " We all agree this feature is desirable, and I would like to ship it as part of the story we tell for the edition. But we also have to prioritize decisions that must be made for the edition (and we are whittling those down quickly, knock on wood). Is this feature inherently edition sensitive on its own? |
Yes, at least if we adopt the "eat-one-layer" model as proposed (and alternative models have their own issues.) |
I've incorporated @traviscross's suggested additions from the 2024-06-26 T-lang design meeting (minutes). We now allow |
We discussed match ergonomics (part 3) in the lang design meeting on 2024-06-26 and came to a consensus on a set of rules. We discussed this further in the triage meeting today, and came to a consensus on a small amendment to Rule 4: Inclusive of that amendment, our consensus is to adopt this slate of rules for match ergonomics:
These rules result in a state transition graph that appears as such. Note that Rule 1 and Rule 2 are edition-dependent and would happen in Rust 2024. The other three rules are backward compatible and would be stabilized in all editions. |
Thank you for the extensive work you put into this RFC, @Jules-Bertholet, and to @traviscross for framing and driving consensus on the remaining details. I'm very impressed by the attention to detail you put into the work and by how well you collaborated with one another and with @Nadrieril, @rpjohnst, and others to get it over the line. I'm extremely happy with the result and with how confident I feel in it now. It looks like we have consensus on the rules as put forth in this RFC. @rfcbot resolve what tradeoff are we making with the " Part of the rationale of accepting this RFC as it is has now become the convergence of at least three different lines of reasoning: The one put forth in this RFC, the one put forth by @traviscross in the most recent lang design meeting on the topic, and the design axioms shared by @Nadrieril in Zulip after the meeting. I would strongly suggest including links to the latter two in the RFC itself, because not only do they strengthen its case, they provide alternative framings for understanding both the problem space of the proposal and the mindset of those around the lang team when it was accepted. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
The final comment period, with a disposition to merge, as per the review above, is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. This will be merged soon. |
In the lang design meeting on 2024-06-26, we adopted a slate of five rules for match ergonomics. We later amended *Rule 4* in our meeting on 2024-07-03. These five rules, as amended, form the normative description of what the lang team means for the rules to be. Therefore, in the reference-level explanation, let's include these rules verbatim and note that the remaining sections describe these rules further.
eeb7d2f
to
28b91fb
Compare
The lang team has accepted this RFC and it's now been merged. Thanks to @Jules-Bertholet for pushing this important work forward, and thanks to @Nadrieril for earlier work here. For further updates, follow the tracking issue: |
Thanks to everyone for this, I'm really looking forward to this change.
…On Sun, Jul 14, 2024, at 2:34 AM, Travis Cross wrote:
The lang team has accepted this RFC and it's now been *merged*.
Thanks to @Jules-Bertholet <https://github.com/Jules-Bertholet> for pushing this important work forward, and thanks to @Nadrieril <https://github.com/Nadrieril> for earlier work here.
For further updates, follow the tracking issue:
• rust-lang/rust#123076 <rust-lang/rust#123076>
—
Reply to this email directly, view it on GitHub <#3627 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AABF4ZQ3QZ5E4KGO6QEL7Y3ZMILVRAVCNFSM6AAAAABHJXJXDGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMRXGIYTGNBWHE>.
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
Rendered
Changes to match ergonomics for the 2024 edition.
@rustbot label T-lang A-patterns A-edition-2024
Tracking: