From a20d5e70433a8b032aa7c4be9c2197fb65f251f0 Mon Sep 17 00:00:00 2001 From: Mazdak Date: Thu, 18 Jan 2018 04:34:30 +0100 Subject: [PATCH 1/8] rfc, tuple_struct_self_ctor: initial version --- 0000-tuple-struct-self-ctor.md | 198 +++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 0000-tuple-struct-self-ctor.md diff --git a/0000-tuple-struct-self-ctor.md b/0000-tuple-struct-self-ctor.md new file mode 100644 index 00000000000..4350310aea7 --- /dev/null +++ b/0000-tuple-struct-self-ctor.md @@ -0,0 +1,198 @@ +- Feature Name: tuple_struct_self_ctor +- Start Date: 2017-01-18 +- RFC PR: (leave this empty) +- Rust Issue: (leave this empty) + +# Summary +[summary]: #summary + +Tuple `struct`s can now be constructed with `Self(v1, v2, ..)` +to match how `struct`s with named fields can be constructed +using `Self { f1: v1, f2: v2, .. }`. A simple example: + +```rust +struct TheAnswer(usize); + +impl Default for TheAnswer { + fn default() -> Self { Self(42) } +} +``` + +# Motivation +[motivation]: #motivation + +This RFC proposes a consistency fix allowing `Self` to be used in more +places to better match the users' intuition of the language and to get +closer to feature parity between tuple structs and structs with named fields. + +Currently, only structs with named fields can be constructed inside +impls using `Self` like so: + +```rust +struct Mascot { name: String, age: usize } + +impl Default for Mascot { + fn default() -> Self { + Self { + name: "Ferris the Crab".into(), + age: 3 + } + } +} +``` + +while the following is not allowed: + +```rust +struct Mascot(String, usize); + +impl Default for Mascot { + fn default() -> Self { + Self("Ferris the Crab".into(), 3) + } +} +``` + +This discrepancy is unfortunate as many users reach for `Self(v0, v1, ..)` +from time to time, only to find that it doesn't work. This creates a break +in the users intuition and becomes a papercut. It also has the effect that +each user must remember this exception, making the rule-set to remember +larger wherefore the language becomes more complex. + +There are good reasons why `Self { f0: v0, f1: v1, .. }` is allowed. +Chiefly among those is that it becomes easier to refactor the code when +one wants to rename type names. Another important reason is that only +having to keep `Self` in mind means that a developer does not need to +keep the type name fresh in their working memory. This is beneficial for +users with shorter working memory such as the author of this RFC. + +Since `Self { f0: v0, .. }` is well motivated, those benefits and motivations +will also extend to tuple structs. Eliminating this discrepancy between tuple +structs and those with named fields will therefore have all the benefits +associated with this feature for structs with named fields. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +## Basic concept + +For structs with named fields such as: + +```rust +struct Person { + name: String, + ssn: usize, + age: usize +} +``` + +You may use the syntax `Self { field0: value0, .. }` as seen below +instead of writing `TypeName { field0: value0, .. }`: + +```rust +impl Person { + /// Make a newborn person. + fn newborn(name: String, ssn: usize) -> Self { + Self { name, ssn, age: 0 } + } +} +``` + +## Through type aliases + +This ability does not extend to tuple structs however in current Rust but will +with this RFC. To continue on with the previous example, you can now also write: + +```rust +struct Person(String, usize, usize); + +impl Person { + /// Make a newborn person. + fn newborn(name: String, ssn: usize) -> Self { + Self(name, ssn, 0) + } +} +``` + +As with structs with named fields, you may also use `Self` when +you are `impl`ing on a type alias of a struct as seen here: + +```rust +struct FooBar(u8); + +type BarFoo = FooBar; + +impl Default for BarFoo { + fn default() -> Self { + Self(42) // <-- Not allowed before. + } +} +``` + +## Teaching the contents + +This RFC should not require additional effort other than spreading the +news that this now is possible as well as the reference. The changes are +seen as intuitive enough that it supports what the user already assumes +should work and will probably try at some point. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +Rust (now) allows usage of `Self(v0, v1, ..)` inside inherent +and trait `impl`s of tuple structs, either when mentioning the +tuple struct directly in the `impl` header, or via a type alias. + +## Desugaring + +When the compiler encounters the syntactic following form specified in `EBNF`: + +```ebnf +SelfTupleApply ::= "Self" "(" ExprList ")" ; +ExprList ::= Expr "," Values | Expr | "" ; +``` + +the compiler will desugar the application by substituting `Self(v0, v1, ..)` +for `Self { 0: v0, 1: v1, .. }` and then continue on from there. The compiler +is however free to use more direct or other approaches as long as it preserves +the semantics of desugaring to `Self { 0: v0, 1: v1, .. }`. + +## In relation to other RFCs + +This RFC expands on [RFC 593] and [RFC 1647] with +respect to where the keyword `Self` is allowed. + +[RFC 593]: 0593-forbid-Self-definitions.md +[RFC 1647]: 1647-allow-self-in-where-clauses.md + +# Drawbacks +[drawbacks]: #drawbacks + +There are potentially some, but the author could not think of any. + +# Rationale and alternatives +[alternatives]: #alternatives + +This is the only design that makes sense in the sense that there really +aren't any other. Potentially, `Self(v0, ..)` should only work when the +`impl`ed type is not behind a type alias. However, since structs with named +fields supports type aliases in this respect, so should tuple structs. + +Not providing this feature would preserve papercuts +and unintuitive surprises for developers. + +# Unresolved questions +[unresolved]: #unresolved-questions + +The following questions should be resolved during the RFC period: + ++ Are there any syntactic ambiguities? + +To the author's knowledge, there are none since following fails to compile today: + +```rust +fn Self(x: u8) {} // <-- an error here since Self is a keyword. + +struct F(u8); +impl F { fn x() { Self(0) } } +``` \ No newline at end of file From 21e3dd9b47e182853a24aae74c248c16e182cb50 Mon Sep 17 00:00:00 2001 From: Mazdak Date: Thu, 18 Jan 2018 04:37:03 +0100 Subject: [PATCH 2/8] rfc, tuple_struct_self_ctor: moved into text/ --- .../0000-tuple-struct-self-ctor.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename 0000-tuple-struct-self-ctor.md => text/0000-tuple-struct-self-ctor.md (100%) diff --git a/0000-tuple-struct-self-ctor.md b/text/0000-tuple-struct-self-ctor.md similarity index 100% rename from 0000-tuple-struct-self-ctor.md rename to text/0000-tuple-struct-self-ctor.md From e35521e9d9670bdc909b0b30c0b976a372b68f7d Mon Sep 17 00:00:00 2001 From: Mazdak Date: Thu, 18 Jan 2018 04:58:06 +0100 Subject: [PATCH 3/8] rfc, tuple_struct_self_ctor: fixed word order (grammar) --- text/0000-tuple-struct-self-ctor.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-tuple-struct-self-ctor.md b/text/0000-tuple-struct-self-ctor.md index 4350310aea7..abed1941fa5 100644 --- a/text/0000-tuple-struct-self-ctor.md +++ b/text/0000-tuple-struct-self-ctor.md @@ -145,7 +145,7 @@ tuple struct directly in the `impl` header, or via a type alias. ## Desugaring -When the compiler encounters the syntactic following form specified in `EBNF`: +When the compiler encounters the following syntactic form specified in `EBNF`: ```ebnf SelfTupleApply ::= "Self" "(" ExprList ")" ; From 891e16abf3859cfa3e70e487ef625d0820d67dd9 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 21 Jun 2018 05:47:11 +0200 Subject: [PATCH 4/8] rfc, tuple-struct-self-ctor: support Self as an fn pointer, support unit structs, change reference explanation, etc. + consequence changes. --- text/0000-tuple-struct-self-ctor.md | 225 ++++++++++++++++++++++++---- 1 file changed, 196 insertions(+), 29 deletions(-) diff --git a/text/0000-tuple-struct-self-ctor.md b/text/0000-tuple-struct-self-ctor.md index abed1941fa5..5911e3700c3 100644 --- a/text/0000-tuple-struct-self-ctor.md +++ b/text/0000-tuple-struct-self-ctor.md @@ -6,9 +6,8 @@ # Summary [summary]: #summary -Tuple `struct`s can now be constructed with `Self(v1, v2, ..)` -to match how `struct`s with named fields can be constructed -using `Self { f1: v1, f2: v2, .. }`. A simple example: +Tuple `struct`s can now be constructed and pattern matched with +`Self(v1, v2, ..)`. A simple example: ```rust struct TheAnswer(usize); @@ -18,6 +17,8 @@ impl Default for TheAnswer { } ``` +Similarly, unit structs can also be constructed and pattern matched with `Self`. + # Motivation [motivation]: #motivation @@ -67,8 +68,8 @@ keep the type name fresh in their working memory. This is beneficial for users with shorter working memory such as the author of this RFC. Since `Self { f0: v0, .. }` is well motivated, those benefits and motivations -will also extend to tuple structs. Eliminating this discrepancy between tuple -structs and those with named fields will therefore have all the benefits +will also extend to tuple and unit structs. Eliminating this discrepancy between +tuple structs and those with named fields will therefore have all the benefits associated with this feature for structs with named fields. # Guide-level explanation @@ -129,6 +130,90 @@ impl Default for BarFoo { } ``` +## Patterns + +Currently, you can pattern match using `Self { .. }` on a named struct as in +the following example: + +```rust +struct Person { + ssn: usize, + age: usize +} + +impl Person { + /// Make a newborn person. + fn newborn(ssn: usize) -> Self { + match { Self { ssn, age: 0 } } { + Self { ssn, age } // `Self { .. }` is permitted as a pattern! + => Self { ssn, age } + } + } +} +``` + +This RFC extends this to tuple structs: + +```rust +struct Person(usize, usize); + +impl Person { + /// Make a newborn person. + fn newborn(ssn: usize) -> Self { + match { Self(ssn, 0) } { + Self(ssn, age) // `Self(..)` is permitted as a pattern! + => Self(ssn, age) + } + } +} +``` + +Of course, this redundant reconstruction is not recommended in actual code, +but illustrates what you can do. + +## `Self` as a function pointer + +When you define a tuple struct today such as: + +```rust +struct Foo(T); + +impl Foo { + fn fooify_iter(iter: impl Iterator) -> impl Iterator> { + iter.map(Foo) + } +} +``` + +you can use `Foo` as a function pointer typed at: `for fn(T) -> T` as +seen in the example above. + +This RFC extends that such that `Self` can also be used as a function pointer +for tuple structs. Modifying the example above gives us: + +```rust +impl Foo { + fn fooify_iter(iter: impl Iterator) -> impl Iterator> { + iter.map(Self) + } +} +``` + +## Unit structs + +With this RFC, you can also use `Self` in pattern and expression contexts when +dealing with unit structs. For example: + +```rust +struct TheAnswer; + +impl Default for TheAnswer { + fn default() -> Self { + match { Self } { Self => Self } + } +} +``` + ## Teaching the contents This RFC should not require additional effort other than spreading the @@ -139,23 +224,116 @@ should work and will probably try at some point. # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -Rust (now) allows usage of `Self(v0, v1, ..)` inside inherent -and trait `impl`s of tuple structs, either when mentioning the -tuple struct directly in the `impl` header, or via a type alias. +Rust (now) allows usage of `Self(v0, v1, ..)` inside inherent and +trait `impl`s of tuple structs, either when mentioning the tuple struct +directly in the `impl` header, or via a type alias. +This usage is permitted both in expression and pattern contexts. + +Furthermore, `Self`, when referring to a tuple struct, can be legally coerced +into an `fn` pointer which accepts and returns expressions of the same type as +the function pointer `Self` is referring to accepts. + +A unit struct defined as `struct $ident;` can similarly be referred +to as by `Self` in expression and pattern contexts inside inherent +and trait `impl`s. + +## Grammar + +Given: + +``` +%token SELF +``` + +which lexes `Self`, the following are legal productions in the language: + +``` +pat : ... // <-- The original grammar of `pat` prior to this RFC. + | SELF '(' ')' + | SELF '(' pat_tup ')' + | SELF + | ... + ; + +expr : ... // <-- Original grammar of `expr`. + | SELF '(' maybe_exprs ')' + | ... + ; +``` + +## Semantics - Expression contexts + +The semantics of the syntax `Self(x_0, .., x_n)` is defined by adding into the +value namespace, if `Self` refers to a tuple struct, a function: -## Desugaring +```rust +const fn Self(x_0: τ_0, .. x: τ_n) -> Self { + Self { 0: x_0, .. n: x_n } +} +``` -When the compiler encounters the following syntactic form specified in `EBNF`: +The semantics of `Self` is defined by adding into the value namespace, +if `Self` refers to a unit struct: -```ebnf -SelfTupleApply ::= "Self" "(" ExprList ")" ; -ExprList ::= Expr "," Values | Expr | "" ; +```rust +const Self: Self = Self {}; ``` -the compiler will desugar the application by substituting `Self(v0, v1, ..)` -for `Self { 0: v0, 1: v1, .. }` and then continue on from there. The compiler -is however free to use more direct or other approaches as long as it preserves -the semantics of desugaring to `Self { 0: v0, 1: v1, .. }`. +## Semantics - Pattern contexts + +In a pattern context, the pattern `Self(x_0, .., x_n)` is desugared to the +pattern `Self { 0: v0, 1: v1, .. }`. Similarly, the pattern `Self` is desugared +to `Self {}`. A rust compiler is free to use different mechanics as these +semantics are preserved. + +## Implementation notes + +As an additional check on the sanity of a Rust compiler implementation, +a well formed expression `Self(v0, v1, ..)`, must be semantically equivalent to +`Self { 0: v0, 1: v1, .. }` and must also be permitted when the latter would. +Likewise the pattern `Self(p0, p1, ..)` must match exactly the same set of +values as `Self { 0: p0, 1: p1, .. }` would and must be permitted when +`Self { 0: p0, 1: p1, .. }` is well formed. + +Furthermore, a well formed expression or pattern `Self` must be semantically +equivalent to `Self {}` and permitted when `Self {}` is well formed in the +same context. + +For example for tuple structs, we have the typing rule: + +``` +Δ ⊢ τ_0 type .. Δ ⊢ τ_n type +Δ ⊢ Self type +Γ ⊢ x_0 : τ_0 .. Γ ⊢ x_n : τ_n +Γ ⊢ Self { 0: x_0, .. n: x_n } : Self +----------------------------------------- +Γ ⊢ Self ( x_0, .., x_n ) : Self +``` + +and the operational semantics: + +``` +Γ ⊢ Self { 0: e_0, .., n: e_n } ⇓ v +------------------------------------- +Γ ⊢ Self { e_0, .., e_n } ⇓ v +``` + +for unit structs, the following holds: + +``` +Δ ⊢ Self type +Γ ⊢ Self {} : Self +----------------------------------------- +Γ ⊢ Self : Self +``` + +with the operational semantics: + +``` +Γ ⊢ Self {} ⇓ v +------------------------------------- +Γ ⊢ Self ⇓ v +``` ## In relation to other RFCs @@ -184,15 +362,4 @@ and unintuitive surprises for developers. # Unresolved questions [unresolved]: #unresolved-questions -The following questions should be resolved during the RFC period: - -+ Are there any syntactic ambiguities? - -To the author's knowledge, there are none since following fails to compile today: - -```rust -fn Self(x: u8) {} // <-- an error here since Self is a keyword. - -struct F(u8); -impl F { fn x() { Self(0) } } -``` \ No newline at end of file +There are none. From d7272b4146eabc28ee086d963075f3d3f8f90e61 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 21 Jun 2018 18:40:52 +0200 Subject: [PATCH 5/8] rfc, tuple-struct-self-ctor: clarify meaning of (now). --- text/0000-tuple-struct-self-ctor.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/text/0000-tuple-struct-self-ctor.md b/text/0000-tuple-struct-self-ctor.md index 5911e3700c3..e296a7f49cc 100644 --- a/text/0000-tuple-struct-self-ctor.md +++ b/text/0000-tuple-struct-self-ctor.md @@ -224,7 +224,8 @@ should work and will probably try at some point. # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -Rust (now) allows usage of `Self(v0, v1, ..)` inside inherent and +With this RFC implemented, +rust allows usage of `Self(v0, v1, ..)` inside inherent and trait `impl`s of tuple structs, either when mentioning the tuple struct directly in the `impl` header, or via a type alias. This usage is permitted both in expression and pattern contexts. From bcd03b23cf54c8bbb36c27bb7498de2dd2d6d405 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 21 Jun 2018 19:41:26 +0200 Subject: [PATCH 6/8] rfc, tuple-struct-self-ctor: reword reference a bit and simplify pattern semantics. --- text/0000-tuple-struct-self-ctor.md | 48 +++++++++-------------------- 1 file changed, 14 insertions(+), 34 deletions(-) diff --git a/text/0000-tuple-struct-self-ctor.md b/text/0000-tuple-struct-self-ctor.md index e296a7f49cc..cb5518ab625 100644 --- a/text/0000-tuple-struct-self-ctor.md +++ b/text/0000-tuple-struct-self-ctor.md @@ -224,20 +224,6 @@ should work and will probably try at some point. # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -With this RFC implemented, -rust allows usage of `Self(v0, v1, ..)` inside inherent and -trait `impl`s of tuple structs, either when mentioning the tuple struct -directly in the `impl` header, or via a type alias. -This usage is permitted both in expression and pattern contexts. - -Furthermore, `Self`, when referring to a tuple struct, can be legally coerced -into an `fn` pointer which accepts and returns expressions of the same type as -the function pointer `Self` is referring to accepts. - -A unit struct defined as `struct $ident;` can similarly be referred -to as by `Self` in expression and pattern contexts inside inherent -and trait `impl`s. - ## Grammar Given: @@ -262,30 +248,24 @@ expr : ... // <-- Original grammar of `expr`. ; ``` -## Semantics - Expression contexts - -The semantics of the syntax `Self(x_0, .., x_n)` is defined by adding into the -value namespace, if `Self` refers to a tuple struct, a function: - -```rust -const fn Self(x_0: τ_0, .. x: τ_n) -> Self { - Self { 0: x_0, .. n: x_n } -} -``` +## Semantics -The semantics of `Self` is defined by adding into the value namespace, -if `Self` refers to a unit struct: +When entering one of the following contexts, a Rust compiler will extend +the value namespace with `Self` which maps to the tuple constructor `fn` +in the case of tuple struct, or a constant, in the case of a unit struct: -```rust -const Self: Self = Self {}; -``` ++ inherent `impl`s where the `Self` type is a tuple or unit struct ++ `trait` `impl`s where the `Self` type is a tuple or unit struct -## Semantics - Pattern contexts +As a result, when referring to a tuple struct, `Self` can be legally coerced +into an `fn` pointer which accepts and returns expressions of the same type as +the function pointer `Self` is referring to accepts. -In a pattern context, the pattern `Self(x_0, .., x_n)` is desugared to the -pattern `Self { 0: v0, 1: v1, .. }`. Similarly, the pattern `Self` is desugared -to `Self {}`. A rust compiler is free to use different mechanics as these -semantics are preserved. +Another consequence is that `Self(p_0, .., p_n)` and `Self` become +legal patterns. This works since `TupleCtor(p_0, .., p_n)` patterns are +handled by resolving them in the value namespace and checking that they +resolve to a tuple constructor. Since by definition, `Self` referring +to a tuple struct resolves to a tuple constructor, this is OK. ## Implementation notes From 41372eefcd8b727810253f17162cb90f90919006 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 21 Jun 2018 20:14:46 +0200 Subject: [PATCH 7/8] rfc, tuple-struct-self-ctor: remove redundant `## Grammar` section in reference. --- text/0000-tuple-struct-self-ctor.md | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/text/0000-tuple-struct-self-ctor.md b/text/0000-tuple-struct-self-ctor.md index cb5518ab625..30a5d4324f2 100644 --- a/text/0000-tuple-struct-self-ctor.md +++ b/text/0000-tuple-struct-self-ctor.md @@ -224,32 +224,6 @@ should work and will probably try at some point. # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -## Grammar - -Given: - -``` -%token SELF -``` - -which lexes `Self`, the following are legal productions in the language: - -``` -pat : ... // <-- The original grammar of `pat` prior to this RFC. - | SELF '(' ')' - | SELF '(' pat_tup ')' - | SELF - | ... - ; - -expr : ... // <-- Original grammar of `expr`. - | SELF '(' maybe_exprs ')' - | ... - ; -``` - -## Semantics - When entering one of the following contexts, a Rust compiler will extend the value namespace with `Self` which maps to the tuple constructor `fn` in the case of tuple struct, or a constant, in the case of a unit struct: From 1951919d2e2e7f586e46eea10ac2e3a34d301422 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 2 Jul 2018 19:37:35 +0200 Subject: [PATCH 8/8] RFC 2302 --- ...e-struct-self-ctor.md => 2302-tuple-struct-self-ctor.md} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename text/{0000-tuple-struct-self-ctor.md => 2302-tuple-struct-self-ctor.md} (97%) diff --git a/text/0000-tuple-struct-self-ctor.md b/text/2302-tuple-struct-self-ctor.md similarity index 97% rename from text/0000-tuple-struct-self-ctor.md rename to text/2302-tuple-struct-self-ctor.md index 30a5d4324f2..85b26c5df02 100644 --- a/text/0000-tuple-struct-self-ctor.md +++ b/text/2302-tuple-struct-self-ctor.md @@ -1,7 +1,7 @@ -- Feature Name: tuple_struct_self_ctor +- Feature Name: `tuple_struct_self_ctor` - Start Date: 2017-01-18 -- RFC PR: (leave this empty) -- Rust Issue: (leave this empty) +- RFC PR: [rust-lang/rfcs#2302](https://github.com/rust-lang/rfcs/pull/2302) +- Rust Issue: [rust-lang/rust#51994](https://github.com/rust-lang/rust/issues/51994) # Summary [summary]: #summary