From ad299816111b563582309ab70a9ca86cea76d4b4 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 23 Jul 2014 21:43:34 +1000 Subject: [PATCH 1/3] RFC for changing the &mut pattern to &mut. --- active/0000-and-mut-patterns.md | 73 +++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 active/0000-and-mut-patterns.md diff --git a/active/0000-and-mut-patterns.md b/active/0000-and-mut-patterns.md new file mode 100644 index 00000000000..8f659179546 --- /dev/null +++ b/active/0000-and-mut-patterns.md @@ -0,0 +1,73 @@ +- Start Date: 23-07-2014 +- RFC PR #: (leave this empty) +- Rust Issue #: (leave this empty) + +# Summary + +Change pattern matching on an `&mut T` to `&mut `, away from its +current `&` syntax. + +# Motivation + +Pattern matching mirrors construction for almost all types, *except* +`&mut`, which is constructed with `&mut ` but destructured with +`&`. This is almost certainly an unnecessary inconsistency. + +This can and does lead to confusion, since people expect the pattern +syntax to match construction, but a pattern like `&mut (ref mut x, _)` is +actually currently a parse error: + +```rust +fn main() { + let &mut (ref mut x, _); +} +``` + +``` +and-mut-pat.rs:2:10: 2:13 error: expected identifier, found path +and-mut-pat.rs:2 let &mut (ref mut x, _); + ^~~ +``` + + +Another (rarer) way it can be confusing is the pattern `&mut x`. It is +expected that this binds `x` to the contents of `&mut T` +pointer... which it does, but as a mutable binding, meaning something +like + +```rust +for &mut x in some_iterator_over_and_mut { + println!("{}", x) +} +``` + +gives an unused mutability warning. NB. it's somewhat rare that one +would want to pattern match to directly bind a name to the contents of +a `&mut` (since the normal reason to have a `&mut` is to mutate the +thing it points at, but this pattern is (byte) copying the data out, +both before and after this change), but can occur if a type only +offers a `&mut` iterator, i.e. types for which a `&` one is no more +flexible than the `&mut` one. + +# Detailed design + +Add ` := &mut ` to the pattern grammar, and require that it is used +when matching on a `&mut T`. + +# Drawbacks + +It makes matching through a `&mut` more verbose: `for &mut (ref mut x, +p_) in v.mut_iter()` instead of `for &(ref mut x, _) in +v.mut_iter()`. + +It is also more verbose if someone does actually want the current +`&mut x` behaviour (of binding the contents to a mutable local): `&mut +mut x`. However, this seems like a very rare edgecase. + +# Alternatives + +None. + +# Unresolved questions + +None. From 33ea11b07c6d64bb02a1b1802e6c3e06f875668d Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Thu, 24 Jul 2014 00:26:19 +1000 Subject: [PATCH 2/3] Clarify current `&mut x` parsing, add macro drawback. --- active/0000-and-mut-patterns.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/active/0000-and-mut-patterns.md b/active/0000-and-mut-patterns.md index 8f659179546..b819ca30512 100644 --- a/active/0000-and-mut-patterns.md +++ b/active/0000-and-mut-patterns.md @@ -32,8 +32,8 @@ and-mut-pat.rs:2 let &mut (ref mut x, _); Another (rarer) way it can be confusing is the pattern `&mut x`. It is expected that this binds `x` to the contents of `&mut T` -pointer... which it does, but as a mutable binding, meaning something -like +pointer... which it does, but as a mutable binding (it is parsed as +`&(mut x)`), meaning something like ```rust for &mut x in some_iterator_over_and_mut { @@ -64,6 +64,12 @@ It is also more verbose if someone does actually want the current `&mut x` behaviour (of binding the contents to a mutable local): `&mut mut x`. However, this seems like a very rare edgecase. +Macros wishing to pattern match on either `&` or `&mut` need to handle +each case, rather than performing both with a single `&`. However, +macros handling these types already need special `mut` vs. not +handling if they ever name the types, or if they use `ref` vs. `ref +mut` subpatterns. + # Alternatives None. From a87116cb6222667e9ac0d8744413f70b1ad9cf77 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 28 Jul 2014 23:05:26 +1000 Subject: [PATCH 3/3] Obtaining the current behaviour is hard in both the `&T` and `&mut T` cases. --- active/0000-and-mut-patterns.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/active/0000-and-mut-patterns.md b/active/0000-and-mut-patterns.md index b819ca30512..0fe0f6c3438 100644 --- a/active/0000-and-mut-patterns.md +++ b/active/0000-and-mut-patterns.md @@ -60,16 +60,20 @@ It makes matching through a `&mut` more verbose: `for &mut (ref mut x, p_) in v.mut_iter()` instead of `for &(ref mut x, _) in v.mut_iter()`. -It is also more verbose if someone does actually want the current -`&mut x` behaviour (of binding the contents to a mutable local): `&mut -mut x`. However, this seems like a very rare edgecase. - Macros wishing to pattern match on either `&` or `&mut` need to handle each case, rather than performing both with a single `&`. However, macros handling these types already need special `mut` vs. not handling if they ever name the types, or if they use `ref` vs. `ref mut` subpatterns. +It also makes obtaining the current behaviour (binding by-value the +contents of a reference to a mutable local) slightly harder. For a +`&mut T` the pattern becomes `&mut mut x`, and, at the moment, for a +`&T`, it must be matched with `&x` and then rebound with `let mut x = +x;` (since disambiguating like `&(mut x)` doesn't yet work). However, +based on some loose grepping of the Rust repo, both of these are very +rare. + # Alternatives None.