From aeaaf9a6783e2dee6323c1fc3143cb320107d0b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Krasnoborski?= Date: Tue, 27 Jan 2015 10:42:58 +0100 Subject: [PATCH 1/3] RFC: Replace `ref` by `*` --- text/0000-replace-ref-by-asterisk.md | 111 +++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 text/0000-replace-ref-by-asterisk.md diff --git a/text/0000-replace-ref-by-asterisk.md b/text/0000-replace-ref-by-asterisk.md new file mode 100644 index 00000000000..6270c104f4f --- /dev/null +++ b/text/0000-replace-ref-by-asterisk.md @@ -0,0 +1,111 @@ +- Start Date: 2015-01-27 +- RFC PR: (leave this empty) +- Rust Issue: (leave this empty) + +# Summary + +Change `ref` in patterns to `*`, to make pattern syntax better match expression syntax. +Example: `Some(ref x)` becomes `Some(*x)`. +This change removes all the usage of `ref` keyword, +so the RFC also discusses the fate of it. + +# Motivation + +In current design, pattern syntax tries to mirror expression syntax +(with some unavoidable `mut` related exceptions), so one may think that +"everything works backwards". But `ref` is an exception here, because: + +* It doesn't appear in expression syntax at all. +* It works "forwards" in contrary to rest of pattern syntax. + +Such an exception may be confusing for a newcommer and even +some more experienced Rust programmer may feel like `ref` doesn't fit pattern syntax well. +Additionaly, one can read both `ref` and `&` as *ref*, but they serve totally different purposes. +That is another source of confusion. + +This RFC proposes to change `ref` to `*` to make this exception disappear. + +Following example shows the symmetry of patterns and expressions in proposed design. +Notice that +the syntax used to reconstruct `x` value is exactly the same as the syntax used to match on in. + +```rust +let x = Some(5); +if let Some(*y) = x { + assert_eq!(Some(*y), x) +} +``` + +Another motivation are opinions, heard from time to time, that `ref` should be called `deref`. + +# Detailed design + +### Interaction with `mut` + +This RFC proposes to change: + +```rust +ref x into *x +ref mut x into mut *x +mut ref x into * mut x +mut ref mut x into mut * mut x +``` + +The rest of pattern syntax stays unchanged. +Notice that in addition to simply changing one token to another, +this RFC also proposes to change placing of `mut` keywords. +The reason for that change is to make `mut` refer to the +thing on the right of `mut`: + +* `mut` keyword in `mut *x` means "dereference of `x` is mutable", because it parses as `mut (*x)`, +* `mut` keyword in `* mut x` means "`x` is mutable reference", because it parses as `*(mut x)`. + +Note that most common usage of `mut` would be `mut *x` here, so the raw-pointer-resembling +`* mut` wouldn't appear very often. +Syntax may allow parenthesised versions too, for consistency / increase of readability. + +### Fate of the `ref` keyword + +The `ref` keyword could simply lose its keyword status, +making it usable as eg. variable or function name +(which might be desired), or it could be repurposed. + +The keyword may be used in some context which deals with +abstracting over different types of references (eg. mutable vs shared or Box vs Rc). + +Other way to repurpose the `ref` keyword is to use it in patterns +as generic deref. Examples: + +```rust +let ref x = Box::new(5); // x == 5 +if let ref [1, _] = vec![1, 2] {} +let rc = Rc::new("abc".into_string()); +let ref *s = rc; // s has a type &String +``` + +Note that this suggestion is not a part of change proposed by the RFC. + +# Drawbacks + +* This is a breaking change, which touches a lot of Rust programs. As Rust is currently already + in alpha, this may be considered a major drawback. However, the change is rather simple + and can be introduced rather painlessly: + * Code upgrade can be done with a simple find and replace (only valid usages of `ref` are in patterns). + * Before beta, old syntax could be accepted while emitting a warning with explanation of change. + It could be also done by making both old and new syntaxes valid and providing a lint for using + the old one. The lint could default to warn for alpha and forbid for beta. + The change has to be reflected also in documentation. +* Ungoogleability. Words *star* and *asterisk* are quite googleable too, although they are more common than *ref*. +* `* mut x` resembles mutable raw pointer syntax (however `mut ref x` pattern is not the common one). + +# Alternatives + +* Do nothing. +* Keep old `mut` order. That makes the change simpler, but (at least for ther author) more confusing. + Also, that would make `*mut` appear more often in patterns, which may be confusing, since + it looks as raw pointer type. + +# Unresolved questions + +* Should we allow additional parenthesis (such as `*(mut x)`) in the syntax? +* Fate of the `ref` keyword (should it be repurposed, reserved or just removed?). From ce2da978d182b8a46cbfeb7b2a6ee3fe6cd227af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Krasnoborski?= Date: Wed, 28 Jan 2015 00:19:39 +0100 Subject: [PATCH 2/3] Add some statistics about `mut ref` usage. Mention discoverability in motivation. --- text/0000-replace-ref-by-asterisk.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/text/0000-replace-ref-by-asterisk.md b/text/0000-replace-ref-by-asterisk.md index 6270c104f4f..334e24491a1 100644 --- a/text/0000-replace-ref-by-asterisk.md +++ b/text/0000-replace-ref-by-asterisk.md @@ -38,6 +38,11 @@ if let Some(*y) = x { Another motivation are opinions, heard from time to time, that `ref` should be called `deref`. +Yet another reason for this change is discoverability -- it's reusing a operator +(while mostly keeping its semantics), +so it's not unlikely for somebody to discover this syntax without consulting a manual. +Actually, there are some users reporting that they tried to use `*` before learning about `ref`. + # Detailed design ### Interaction with `mut` @@ -60,9 +65,13 @@ thing on the right of `mut`: * `mut` keyword in `mut *x` means "dereference of `x` is mutable", because it parses as `mut (*x)`, * `mut` keyword in `* mut x` means "`x` is mutable reference", because it parses as `*(mut x)`. -Note that most common usage of `mut` would be `mut *x` here, so the raw-pointer-resembling -`* mut` wouldn't appear very often. -Syntax may allow parenthesised versions too, for consistency / increase of readability. +Syntax may allow these parenthesised versions too, for consistency / increase of readability. + +Note that most common usage of `mut` would be `mut *x` (corresponding to current `ref mut x`), +so the raw-pointer-resembling `* mut` wouldn't appear very often +(in rust source `ref mut` appears 139 times, compared to only 9 usages of `mut ref`). +Additionally, that resemblance is between *pattern* and *type* syntaxes so it's not that big issue. +Moreover, that pattern should be written with space between `*` and `mut` or use a parenthesized version. ### Fate of the `ref` keyword @@ -96,7 +105,7 @@ Note that this suggestion is not a part of change proposed by the RFC. the old one. The lint could default to warn for alpha and forbid for beta. The change has to be reflected also in documentation. * Ungoogleability. Words *star* and *asterisk* are quite googleable too, although they are more common than *ref*. -* `* mut x` resembles mutable raw pointer syntax (however `mut ref x` pattern is not the common one). +* `* mut x` resembles mutable raw pointer syntax (however it won't appear very often (see explanation above)). # Alternatives From 9ce9ccd8e977a18de10e5d5ca2ba32f1560fb58c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Krasnoborski?= Date: Wed, 28 Jan 2015 07:33:33 +0100 Subject: [PATCH 3/3] Removed fragments about `mut ref`. Explained interaction with `&mut` patterns. --- text/0000-replace-ref-by-asterisk.md | 42 +++++++++++++++++----------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/text/0000-replace-ref-by-asterisk.md b/text/0000-replace-ref-by-asterisk.md index 334e24491a1..4ce4750c23d 100644 --- a/text/0000-replace-ref-by-asterisk.md +++ b/text/0000-replace-ref-by-asterisk.md @@ -47,31 +47,41 @@ Actually, there are some users reporting that they tried to use `*` before learn ### Interaction with `mut` -This RFC proposes to change: +This RFC proposes to change (in contrary to what was suggested before, `mut ref x` is currently not a valid pattern): ```rust ref x into *x ref mut x into mut *x -mut ref x into * mut x -mut ref mut x into mut * mut x ``` -The rest of pattern syntax stays unchanged. Notice that in addition to simply changing one token to another, -this RFC also proposes to change placing of `mut` keywords. +this RFC also proposes to change placing of `mut` keyword. The reason for that change is to make `mut` refer to the -thing on the right of `mut`: +thing on the right of `mut`. `mut` keyword in `mut *x` means "dereference of `x` is mutable", +because it parses as `mut (*x)`. -* `mut` keyword in `mut *x` means "dereference of `x` is mutable", because it parses as `mut (*x)`, -* `mut` keyword in `* mut x` means "`x` is mutable reference", because it parses as `*(mut x)`. +Syntax may allow the parenthesised version too, for consistency / increase of readability. -Syntax may allow these parenthesised versions too, for consistency / increase of readability. +Another problem is interaction with `&mut _` pattern. In the new design, +following would be ambigous to parse: -Note that most common usage of `mut` would be `mut *x` (corresponding to current `ref mut x`), -so the raw-pointer-resembling `* mut` wouldn't appear very often -(in rust source `ref mut` appears 139 times, compared to only 9 usages of `mut ref`). -Additionally, that resemblance is between *pattern* and *type* syntaxes so it's not that big issue. -Moreover, that pattern should be written with space between `*` and `mut` or use a parenthesized version. +```rust +&mut *x +``` + +It could mean either `&mut (*x)` of `&(mut *x)`. Fortunately, under no conditions +right one could compile, so the left version could be assumed. +If the user wanted to have a mutable reference in this case, +they have to write + +```rust +&mut mut *x +``` + +which is unambigous and corresponds to today's `&mut ref mut x`. The double `mut` may seem weird, +but fortunately this pattern is not a common one – it's used only 6 times in rust source, +from which only one is outside tests. +Additionaly this pattern (at least according to the author's knowledge) could be replaced by just `x`. ### Fate of the `ref` keyword @@ -105,7 +115,6 @@ Note that this suggestion is not a part of change proposed by the RFC. the old one. The lint could default to warn for alpha and forbid for beta. The change has to be reflected also in documentation. * Ungoogleability. Words *star* and *asterisk* are quite googleable too, although they are more common than *ref*. -* `* mut x` resembles mutable raw pointer syntax (however it won't appear very often (see explanation above)). # Alternatives @@ -116,5 +125,6 @@ Note that this suggestion is not a part of change proposed by the RFC. # Unresolved questions -* Should we allow additional parenthesis (such as `*(mut x)`) in the syntax? +* Should we allow additional parenthesis (such as `mut (*x)`) in the syntax? +* Should we introduce `*(mut x)` pattern which would put the reference in a mutable slot? * Fate of the `ref` keyword (should it be repurposed, reserved or just removed?).