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 upRFC: `mut (x, y, ..)` and `mut [x, y, ..]` pattern shorthand #2401
Conversation
Centril
added some commits
Apr 13, 2018
Centril
added
the
T-lang
label
Apr 15, 2018
This comment has been minimized.
This comment has been minimized.
|
While this is (mostly) not a problem any more due to the default match bindings, I think that these rules should apply to |
This comment has been minimized.
This comment has been minimized.
|
@clarcharr So the reason why I didn't add that was the default match bindings you mention. However, I don't mind it personally, and if there is consensus within the lang team and within the community, I will certainly add it. |
This comment has been minimized.
This comment has been minimized.
|
Hmm, I'm torn about this statement
On the one hand I like the restriction to "special" types (tuples & arrays), but at the same time patterns nest, so you can still have |
kennytm
reviewed
Apr 15, 2018
| | first binding | ||
| ``` | ||
|
|
||
| ## Reversed polarity with `immut` |
This comment has been minimized.
This comment has been minimized.
kennytm
Apr 15, 2018
Member
We could use const (as in *mut T vs *const T) instead of introducing yet another keyword. (I'm
This comment has been minimized.
This comment has been minimized.
Centril
Apr 15, 2018
Author
Contributor
So the point of this section is to say that we should not introduce immut ;) So I agree entirely with you here that we shouldn't do it.
|
|
||
| None as of yet. | ||
|
|
||
| # Future work |
This comment has been minimized.
This comment has been minimized.
kennytm
Apr 15, 2018
Member
We have recently implemented #554 (rust-lang/rust#48500). Would mut next to a parenthesis pattern be allowed?
match 5 {
mut (x) => {}
}
This comment has been minimized.
This comment has been minimized.
Centril
Apr 15, 2018
Author
Contributor
So looking as parser-lalr.y, we have:
pat
: ...
| '(' pat_tup ')' { $$ = mk_node("PatTup", 1, $2); }which I extended with MUT '(' pat_tup ')'
Then, pat_tup eventually leads to a production MUT '(' pat ')' so it seems that per the grammar I've included in the reference, mut (x) => {} would be permitted.
Is that a good thing or a bad thing..? I don't know. It seems simpler to permit mut (x) even if it is not the recommended style.
This comment has been minimized.
This comment has been minimized.
kennytm
Apr 15, 2018
Member
@Centril the *.y file is not up-to-date though, and (x) isn't a tuple (the 1-tuple syntax is ($pat,)).
This comment has been minimized.
This comment has been minimized.
Centril
Apr 15, 2018
Author
Contributor
Ah damn :/ so my answer can't be reliable here if the *.y file is not up to date.
If we want to do the broader change per @scottmcm's comment above, it makes sense to also permit mut (x). What is your view?
This comment has been minimized.
This comment has been minimized.
kennytm
Apr 15, 2018
•
Member
@Centril I think if parenthesis is allowed, then almost all patterns should support leading mut (except the ambiguous-to-parse stuff like x @ pat, x | y and x..=y) because literally any pattern can appear inside (ā¦).
This comment has been minimized.
This comment has been minimized.
scottmcm
Apr 16, 2018
Member
Hmm, @kennytm's comment pushes me back down to -0 on this, since it reminded me that the proposed grammar will allow all kinds of silliness like mut (1...10, 20...30). That's certainly not a blocking issue -- I'm confident it could be linted without too much trouble -- but does emphasize that the current "mut is part of a binding" rule is substantially simpler.
This comment has been minimized.
This comment has been minimized.
Centril
Apr 16, 2018
Author
Contributor
So thinking about what such a lint could be, an analysis that checks the pattern (1..=10, 20..=30) for bindings would find that there are none, and so a mut in front of it would apply to zero bindings, which would be the lint condition. That's not so complex?
The current rule is for sure simpler tho =)
This comment has been minimized.
This comment has been minimized.
Yeah; I'm torn about this as well, and you make a fine argument. Trying to restrict patterns, like the one you've mentioned, which we might consider unidiomatic will probably just cause hazards for the future. It might be easier wrt. complexity to just do the broader change. I look forward to the community and the lang team's guidance to make me untorn =P |
scottmcm
reviewed
Apr 15, 2018
| also has redundant `mut`s either outside the tuple or inside the tuple. | ||
| When such a redundancy happens, the compiler should unconditionally warn the | ||
| user. Furthermore, when `let mut (x, y)` results in partial unused `mut`ability | ||
| then the compiler should also warn. |
This comment has been minimized.
This comment has been minimized.
scottmcm
Apr 15, 2018
Member
nitpick: I don't think "unconditionally" is appropriate; this can just be an extension of unused_mut (or maybe a new lint, but distinguishing seems unnecessary to me).
So you get something suppressible; maybe
warning: variable is already mutable
--> src/main.rs:2:9
|
2 | let mut (mut x, y) = (4, 5;
| ----^
| |
| help: remove this `mut`
|
= note: #[warn(unused_mut)] on by default
This comment has been minimized.
This comment has been minimized.
Centril
Apr 15, 2018
Author
Contributor
Yeah; I think your comment reflects what I actually meant ;)
This comment has been minimized.
This comment has been minimized.
durka
Apr 18, 2018
•
Contributor
This further reduces the usefulness to macros, though I guess the double-mut warnings could be turned off inside macros.
This comment has been minimized.
This comment has been minimized.
Centril
Apr 18, 2018
Author
Contributor
@durka The standard approach is that you can disable lints with #[allow(..)], and that should be doable inside macros as usual.
This comment has been minimized.
This comment has been minimized.
|
This doesn't look common enough to me to meet the threshold on a language addition. But we can actually estimate the effect on the crates.io ecosystem by writing a deny-by-default lint and running it through crater. |
This comment has been minimized.
This comment has been minimized.
|
By the way, how mut (ref x, ref mut y)
<=>
(mut ref x, mut ref mut y)
<=>
(ref x, ref mut y)
let mut x = x;
let mut y = y;Currently we don't have syntax to do this directly in the pattern. |
This comment has been minimized.
This comment has been minimized.
Sounds like a nice idea. Would you mind taking a crack at it?
I think the interpretation you described is reasonable and is in line with the RFC as currently specified. |
durka
suggested changes
Apr 18, 2018
|
It makes some declarations shorter (though maybe harder to read, IMO), but it feels strange to me because it adds a special case to the pattern syntax, which right now is a nice collection of small composable parts. Paradoxically, I think the radical option ( |
| Another effect of reduced repetition is that it now becomes easy to create | ||
| a macro that introduces mutable bindings everywhere (for tuples and arrays) | ||
| by simply adding a single `mut`. This way, you can take a `pat` fragment and | ||
| prefix it with `mut` to make the entire pattern introduce mutable bindings. |
This comment has been minimized.
This comment has been minimized.
durka
Apr 18, 2018
Contributor
Hi, I annoyingly pop up when people tout spurious and/or exaggerated macro ergonomics as advantages of RFCs.
If this is to actually be supported, it is another feature request (probably a good one, though!). Similar code doesn't currently work because you can't modify an already-parsed nonterminal. That is, this doesn't compile:
macro_rules! m {
($p:pat, $e:expr) => {
let mut $p = $expr; // theory: 'mut' + pat = pat
}
}
m!(x, 42); //~ERROR expected identifier
This comment has been minimized.
This comment has been minimized.
Centril
Apr 18, 2018
Author
Contributor
It seems to me that the problem here is that mut $pat is not valid and mut expects an identifier, i.e: mut $ident. Indeed, the following snippet is valid:
macro_rules! m { ($p:ident, $e:expr) => { let mut $p = $e; } }
fn main() { m!(x, 42); }Any suggestions on how to modify the reference to actually support this case?
PS: ping me on IRC for more sync discussions :)
| also has redundant `mut`s either outside the tuple or inside the tuple. | ||
| When such a redundancy happens, the compiler should unconditionally warn the | ||
| user. Furthermore, when `let mut (x, y)` results in partial unused `mut`ability | ||
| then the compiler should also warn. |
This comment has been minimized.
This comment has been minimized.
durka
Apr 18, 2018
•
Contributor
This further reduces the usefulness to macros, though I guess the double-mut warnings could be turned off inside macros.
| For others, readability will be increased thanks to reduced noise. | ||
| The ability to edit can also be increased when you only need to add `mut` after | ||
| `let` to introduce mutable bindings. A mitigating factor to reduced readability | ||
| for some is the fact that using this new syntax is entirely optional. |
This comment has been minimized.
This comment has been minimized.
durka
Apr 18, 2018
Contributor
"The new syntax is optional" is never a valid argument. If you don't use it, someone else will, and code is read more often than written.
This comment has been minimized.
This comment has been minimized.
Centril
Apr 18, 2018
Author
Contributor
I won't agree to such a sweeping statement - to me there's more nuance. I believe it's a valid argument as a mitigating factor. Yes, code is read more often than written in general, but that also depends on the project. Sometimes code is written and read exactly as much (because you wrote the code for a hobby project, wrote tests for it, and now you can forget about the implementation).
To me, the locality problem was not a particularly serious drawback to begin with; I mention it primarily for the purposes of being exhaustive. On balance, I believe the new introduced syntax improves readability.
| Of course, this way of writing may not be to everyone's liking. | ||
|
|
||
| # Guide-level explanation | ||
| [guide-level-explanation]: #guide-level-explanation |
This comment has been minimized.
This comment has been minimized.
durka
Apr 18, 2018
Contributor
One thing I'm worried about is people assuming that let mut is a unit, rather than let $pat. This probably already happens a ton, since single ident bindings are the most common. But maybe it should be called out in the guide somehow.
This comment has been minimized.
This comment has been minimized.
Centril
Apr 18, 2018
Author
Contributor
I've called it out now at the end of the first subsection. Check it out / Propose improvements?
| and pattern matched on instead of `mut` being prefixed on a lot or all bindings. | ||
| The single `mut` introduced as in `let mut (x, (y, z)) = ..` should still be | ||
| sufficiently close in visual scope to not require holding more things in short | ||
| term memory. |
This comment has been minimized.
This comment has been minimized.
durka
Apr 18, 2018
•
Contributor
I'm not sure about this. Patterns can get pretty long. When I wrote a macro that recursed through patterns, if this feature were included there's an extra bit of state to track, whereas in ye olde patterns, once you found an ident, you could look at the token right before it and know what it was. I guess default binding modes already changed this though. And the fact that it's one-way (mutability only goes on, and can't be reversed deeper in the pattern) reduces the added cognitive overhead somewhat.
This comment has been minimized.
This comment has been minimized.
Centril
Apr 18, 2018
•
Author
Contributor
Often nothing can replace exercising good judgement.
My personal taste is that the method and the specific match arm is significantly too long and should be split up (but I'm from the radical school of 1-10 line functions in Haskell so I'm a bit special .. ). Even so, IMO, the pattern you reference is still close enough in visual scope to not be a problem.
This comment has been minimized.
This comment has been minimized.
|
Just a heads up, we should probably use permalinks to code instead, so the links remain correct even after the code changes in later commits, since the RFC may be longer lived than the code, especially if this RFC is approved and these places are updated to make use of the proposed syntax:
|
Centril
added some commits
Apr 18, 2018
This comment has been minimized.
This comment has been minimized.
|
@blaenk Fixed; Thanks! |
This comment has been minimized.
This comment has been minimized.
leodasvacas
commented
Apr 19, 2018
|
This grep catches the common case for this feature. Some matches are false positives but still there seems to be hundreds of lines of code that could really use this, only in the ~600 crates searched. |
This comment has been minimized.
This comment has been minimized.
sergeysova
commented
Apr 27, 2018
•
|
What about structure destructuring: let mut { foo, bar } = value; |
This comment has been minimized.
This comment has been minimized.
|
@sergeysova That pattern |
This comment has been minimized.
This comment has been minimized.
SoniEx2
commented
May 3, 2018
•
|
Can macros expand to patterns? let (mut_all!(a, b, c)) = (1, 2, 3);
let Foo { mut_all!(a, b, c) } = Foo { a: 1, b: 2, c: 3 };If so, macros have their semantics resolved already, so we should use macros to keep the language simpler. |
This comment has been minimized.
This comment has been minimized.
Update: |
Centril
self-assigned this
Aug 9, 2018
This comment has been minimized.
This comment has been minimized.
|
The more I look at this, the more it feels like an unusual special case that requires a double-take when reading code. When you already have a tuple or slice, it doesn't feel that onerous to have to write And I don't think we should encourage the use of tuples to cram multiple |
This comment has been minimized.
This comment has been minimized.
SoniEx2
commented
Aug 10, 2018
•
|
I actually already use |
This comment has been minimized.
This comment has been minimized.
|
This seems a bit fraught to me. If it were done then I'd vote to do it very conservatively, and make sure it's as uniform and regular as we can make it--nobody likes special cases. |
Centril
added
A-syntax
A-patterns
labels
Nov 22, 2018
This comment has been minimized.
This comment has been minimized.
graydon
commented
Jan 12, 2019
|
Oppose. Needless churn. As the RFC itself asks: "Does the value of this outweigh the cost of having multiple ways to do it". IMO the answer is no. |
This comment has been minimized.
This comment has been minimized.
|
This is a relatively small change to the surface area of the language, but it's still a change, and one that seems inconsistent with where @rfcbot close |
This comment has been minimized.
This comment has been minimized.
rfcbot
commented
Jan 18, 2019
•
|
Team member @joshtriplett has proposed to close this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), 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. |
rfcbot
added
proposed-final-comment-period
disposition-close
labels
Jan 18, 2019
This comment has been minimized.
This comment has been minimized.
rfcbot
commented
Mar 20, 2019
|
|
rfcbot
added
final-comment-period
and removed
proposed-final-comment-period
labels
Mar 20, 2019
This comment has been minimized.
This comment has been minimized.
rfcbot
commented
Mar 30, 2019
|
The final comment period, with a disposition to close, 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. The RFC is now closed. |
Centril commentedApr 15, 2018
This RFC aims to improve ergonomics by allowing you to write:
To @scottmcm, @varkor and others for their review and interesting discussions.