From e91e24dc42093cc2ab5b29fe0c4471645719d641 Mon Sep 17 00:00:00 2001 From: Mazdak Date: Sat, 13 Jan 2018 15:58:25 +0100 Subject: [PATCH 1/7] rfc, associated-type-bounds: initial text --- text/0000-associated-type-bounds.md | 117 ++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 text/0000-associated-type-bounds.md diff --git a/text/0000-associated-type-bounds.md b/text/0000-associated-type-bounds.md new file mode 100644 index 00000000000..6b496044fe1 --- /dev/null +++ b/text/0000-associated-type-bounds.md @@ -0,0 +1,117 @@ +- Feature Name: associated_type_bounds +- Start Date: 2018-01-13 +- RFC PR: (leave this empty) +- Rust Issue: (leave this empty) + +# Summary +[summary]: #summary + +Introduce the bound form `MyTrait`, permitted anywhere +a bound of the form `MyTrait` would be allowed. This form +desugars to `MyTrait`. + +# Motivation +[motivation]: #motivation + +Currently, when specifying a bound using a trait that has an associated +type, the developer can specify the precise type via the syntax +`MyTrait`. With the introduction of the `impl Trait` +syntax for static-dispatch existential types, this syntax also permits +`MyTrait`, as a shorthand for introducing a +new type variable and specifying those bounds. + +However, this introduces an unnecessary level of indirection that does not +match the developer's intuition and mental model as well as it could. In +particular, given the ability to write bounds on a type variable as `T: Bounds`, +it makes sense to permit writing bounds on an associated type directly. +This results in the simpler syntax `MyTrait`. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +Instead of specifying a concrete type for an associated type, we can +specify a bound on the associated type, to ensure that it implements +specific traits, as seen in the example below: + +```rust +fn print_all>(printables: T) { + for p in printables { + println!("{}", p); + } +} +``` + +## In anonymous existential types + +```rust +fn printables() -> impl Iterator { + // .. +} +``` + +## Further examples + +Instead of writing: + +```rust +impl Clone for Peekable +where + I: Clone + Iterator, + ::Item: Clone, +{ + // .. +} +``` + +you may write: + +```rust +impl Clone for Peekable +where + I: Clone + Iterator +{ + // .. +} +``` + +or replace the `where` clause entirely: + +```rust +impl> Clone for Peekable { + // .. +} +``` + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +The surface syntax `Trait` should desugar to +`Trait` anywhere it appears. This syntax +does not introduce any new semantics that the availability of +`impl Bounds` does not already introduce. + +# Drawbacks +[drawbacks]: #drawbacks + +With the introduction of the `impl Trait` syntax, Rust code can already +express this using the desugared form. This proposal just introduces a +simpler surface syntax that parallels other uses of bounds. As always, +when introducing new syntactic forms, an increased burden is put on +developers to know about and understand those forms, and this proposal +is no different. However, we believe that the parallel to the use of bounds +elsewhere makes this new syntax immediately recognizable and understandable. + +# Rationale and alternatives +[alternatives]: #alternatives + +As with any new surface syntax, one alternative is simply not introducing +the syntax at all. That would still leave developers with the +`MyTrait` form. However, allowing the more +direct bounds syntax provides a better parallel to the use of bounds elsewhere. +The introduced form in this RFC is comparatively both shorter and clearer. + +# Unresolved questions +[unresolved]: #unresolved-questions + +- Does this introduce any parsing ambiguities? +- Does allowing this for `dyn` trait objects introduce any unforseen issues? \ No newline at end of file From 244d5aac06021274a97a9c1bcf2cd8bb4d3b0597 Mon Sep 17 00:00:00 2001 From: Mazdak Date: Sat, 13 Jan 2018 20:41:37 +0100 Subject: [PATCH 2/7] rfc, associated-type-bounds: resolve question on syntax ambiguity. --- text/0000-associated-type-bounds.md | 1 - 1 file changed, 1 deletion(-) diff --git a/text/0000-associated-type-bounds.md b/text/0000-associated-type-bounds.md index 6b496044fe1..b9a3042618c 100644 --- a/text/0000-associated-type-bounds.md +++ b/text/0000-associated-type-bounds.md @@ -113,5 +113,4 @@ The introduced form in this RFC is comparatively both shorter and clearer. # Unresolved questions [unresolved]: #unresolved-questions -- Does this introduce any parsing ambiguities? - Does allowing this for `dyn` trait objects introduce any unforseen issues? \ No newline at end of file From f279bac9e2be6505ba015724cbaae1588e89e19e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 5 Mar 2018 17:08:13 +0100 Subject: [PATCH 3/7] rfc, associated_type_bounds: fix desugaring + other house keeping --- text/0000-associated-type-bounds.md | 38 ++++++++++++++++++----------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/text/0000-associated-type-bounds.md b/text/0000-associated-type-bounds.md index b9a3042618c..26dfcfef454 100644 --- a/text/0000-associated-type-bounds.md +++ b/text/0000-associated-type-bounds.md @@ -7,8 +7,9 @@ [summary]: #summary Introduce the bound form `MyTrait`, permitted anywhere -a bound of the form `MyTrait` would be allowed. This form -desugars to `MyTrait`. +a bound of the form `MyTrait` would be allowed. The bound +`T: Trait` desugars to the bounds `T: Trait` and +`::AssociatedType: Bounds`. # Motivation [motivation]: #motivation @@ -85,21 +86,29 @@ impl> Clone for Peekable { # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -The surface syntax `Trait` should desugar to -`Trait` anywhere it appears. This syntax -does not introduce any new semantics that the availability of -`impl Bounds` does not already introduce. +The surface syntax `T: Trait` should always desugar +to a pair of bounds: `T: Trait` and `::AssociatedType: Bounds`. +Rust currently allows both of those bounds anywhere a bound can currently appear; +the new syntax does not introduce any new semantics. + +Additionally, the surface syntax `impl Trait` turns +into a named type variable `T`, universal or existential depending on context, +with the usual bound `T: Trait` along with the added bound +`::AssociatedType: Bounds`. + +Meanwhile, the surface syntax `dyn Trait` desugars into +`dyn Trait` where `T` is a named type variable `T` with the +bound `T: Bounds`. # Drawbacks [drawbacks]: #drawbacks -With the introduction of the `impl Trait` syntax, Rust code can already -express this using the desugared form. This proposal just introduces a -simpler surface syntax that parallels other uses of bounds. As always, -when introducing new syntactic forms, an increased burden is put on -developers to know about and understand those forms, and this proposal -is no different. However, we believe that the parallel to the use of bounds -elsewhere makes this new syntax immediately recognizable and understandable. +Rust code can already express this using the desugared form. This proposal +just introduces a simpler surface syntax that parallels other uses of bounds. +As always, when introducing new syntactic forms, an increased burden is put on +developers to know about and understand those forms, and this proposal is no +different. However, we believe that the parallel to the use of bounds elsewhere +makes this new syntax immediately recognizable and understandable. # Rationale and alternatives [alternatives]: #alternatives @@ -113,4 +122,5 @@ The introduced form in this RFC is comparatively both shorter and clearer. # Unresolved questions [unresolved]: #unresolved-questions -- Does allowing this for `dyn` trait objects introduce any unforseen issues? \ No newline at end of file +- Does allowing this for `dyn` trait objects introduce any unforseen issues? + This can be resolved during stabilization. \ No newline at end of file From 95d569a5157477de2d84d90ff0370abadec12f84 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 8 Jun 2018 02:10:39 +0200 Subject: [PATCH 4/7] rfc, associated-type-bounds: clarify a bunch of things / leave some things unresolved. --- text/0000-associated-type-bounds.md | 122 ++++++++++++++++++++++++++-- 1 file changed, 117 insertions(+), 5 deletions(-) diff --git a/text/0000-associated-type-bounds.md b/text/0000-associated-type-bounds.md index 26dfcfef454..24ef2871470 100644 --- a/text/0000-associated-type-bounds.md +++ b/text/0000-associated-type-bounds.md @@ -10,6 +10,8 @@ Introduce the bound form `MyTrait`, permitted anywhere a bound of the form `MyTrait` would be allowed. The bound `T: Trait` desugars to the bounds `T: Trait` and `::AssociatedType: Bounds`. +See the [reference][reference-level-explanation] and [rationale][alternatives] +for exact details. # Motivation [motivation]: #motivation @@ -86,8 +88,8 @@ impl> Clone for Peekable { # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -The surface syntax `T: Trait` should always desugar -to a pair of bounds: `T: Trait` and `::AssociatedType: Bounds`. +The surface syntax `T: Trait` should desugar to a pair +of bounds: `T: Trait` and `::AssociatedType: Bounds`. Rust currently allows both of those bounds anywhere a bound can currently appear; the new syntax does not introduce any new semantics. @@ -100,6 +102,53 @@ Meanwhile, the surface syntax `dyn Trait` desugars into `dyn Trait` where `T` is a named type variable `T` with the bound `T: Bounds`. +## The desugaring for associated types + +In the case of an associated type having a bound of the form: + +```rust +trait TraitA { + type AssocA: TraitB; +} +``` + +we desugar to an anonymous associated type for `AssocB`, which corresponds to: + +```rust +trait TraitA { + type AssocA: TraitB; + type AssocA_0: TraitC; // Associated type is Unnamed! +} +``` + +## Notes on the meaning of `impl Trait` + +Note that in the context `-> impl Trait`, since the +`Trait` is existentially quantified, so is in effect also the `Assoc`. +Semantically speaking, `fn printables..` is equivalent to: + +```rust +fn printables() -> impl Iterator { .. } +``` + +For `arg: impl Trait`, it can likewise be seen as: +`arg: impl Trait`. + +## Meaning of `existential type Foo: Trait` + +Given: + +``` +existential type Foo: Trait; +``` + +it can be seen as the same as: + +```rust +existential type Foo: Trait; +existential type _0: Bound; +``` + # Drawbacks [drawbacks]: #drawbacks @@ -111,7 +160,7 @@ different. However, we believe that the parallel to the use of bounds elsewhere makes this new syntax immediately recognizable and understandable. # Rationale and alternatives -[alternatives]: #alternatives +[alternatives]: #rationale-and-alternatives As with any new surface syntax, one alternative is simply not introducing the syntax at all. That would still leave developers with the @@ -119,8 +168,71 @@ the syntax at all. That would still leave developers with the direct bounds syntax provides a better parallel to the use of bounds elsewhere. The introduced form in this RFC is comparatively both shorter and clearer. +### An alternative desugaring of bounds on associated types + +[RFC 2089]: https://github.com/rust-lang/rfcs/blob/master/text/2089-implied-bounds.md + +An alternative desugaring of the following definition: + +```rust +trait TraitA { + type AssocA: TraitB; +} +``` + +is to add the `where` clause, as specified above, to the trait, desugaring to: + +```rust +trait TraitA +where + ::AssocB: TraitC, +{ + type AssocA: TraitB; +} +``` + +However, at the time of this writing, a Rust compiler will treat this +differently than the desugaring proposed in the reference. +The following snippet illustrates the difference: + +```rust +trait Foo where ::Item: Copy { + type Bar: Iterator; +} + +trait Foo2 { + type Bar: Iterator; + type BarItem: Copy; +} + +fn use_foo(arg: X) +where ::Item: Copy +// ^-- Remove this line and it will error with: +// error[E0277]: `<::Bar as std::iter::Iterator>::Item` doesn't implement `Copy` +{ + let item: ::Item; +} + +fn use_foo2(arg: X) { + let item: ::Item; +} +``` + +The desugaring with a `where` therefore becomes problematic from a perspective +of usability. + +However, [RFC 2089, Implied Bounds][RFC 2089] specifies that desugaring to the +`where` clause in the trait will permit the `use_foo` function to omit its +`where` clause. This entails that both desugarings become equivalent from the +point of view of a user. The desugaring with `where` therefore becomes viable +in the presence of [RFC 2089]. + # Unresolved questions [unresolved]: #unresolved-questions -- Does allowing this for `dyn` trait objects introduce any unforseen issues? - This can be resolved during stabilization. \ No newline at end of file +- Does allowing this for `dyn` trait objects introduce any unforeseen issues? + This can be resolved during stabilization. + +- The exact desugaring in the context of putting bounds on an associated type + of a trait is left unresolved. The semantics should however be preserved. + This is also the case with other desugarings in this RFC. From 46822165ed3afa2c25cbfae1fb2c4f73e555ceaa Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 8 Jun 2018 02:24:20 +0200 Subject: [PATCH 5/7] rfc, associated-type-bounds: improve grammar + link to RFC 2071 (+ notes about it..) --- text/0000-associated-type-bounds.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/text/0000-associated-type-bounds.md b/text/0000-associated-type-bounds.md index 24ef2871470..22521391145 100644 --- a/text/0000-associated-type-bounds.md +++ b/text/0000-associated-type-bounds.md @@ -123,9 +123,9 @@ trait TraitA { ## Notes on the meaning of `impl Trait` -Note that in the context `-> impl Trait`, since the -`Trait` is existentially quantified, so is in effect also the `Assoc`. -Semantically speaking, `fn printables..` is equivalent to: +Note that in the context `-> impl Trait`, since the Trait is +existentially quantified, the `Assoc` is as well. Semantically speaking, +`fn printables..` is equivalent to: ```rust fn printables() -> impl Iterator { .. } @@ -149,6 +149,11 @@ existential type Foo: Trait; existential type _0: Bound; ``` +[RFC 2071]: https://github.com/rust-lang/rfcs/blob/master/text/2071-impl-trait-type-alias.md + +This syntax is specified in [RFC 2071]. As in that RFC, this documentation +uses the non-final syntax for existential type aliases. + # Drawbacks [drawbacks]: #drawbacks From fb31e7e1a0e2207db83070a77573eb5ce2c18b47 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 8 Jun 2018 02:33:33 +0200 Subject: [PATCH 6/7] rfc, associated-type-bounds: phrasing consistency of impl Trait stuff. --- text/0000-associated-type-bounds.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-associated-type-bounds.md b/text/0000-associated-type-bounds.md index 22521391145..3c00eb7250d 100644 --- a/text/0000-associated-type-bounds.md +++ b/text/0000-associated-type-bounds.md @@ -131,7 +131,7 @@ existentially quantified, the `Assoc` is as well. Semantically speaking, fn printables() -> impl Iterator { .. } ``` -For `arg: impl Trait`, it can likewise be seen as: +For `arg: impl Trait`, it is semantically equivalent to: `arg: impl Trait`. ## Meaning of `existential type Foo: Trait` From 2a685b5cb375a3f1bba7da1e76396afb6263db68 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 24 Jul 2018 13:46:37 +0200 Subject: [PATCH 7/7] RFC 2289 --- ...ciated-type-bounds.md => 2289-associated-type-bounds.md} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename text/{0000-associated-type-bounds.md => 2289-associated-type-bounds.md} (97%) diff --git a/text/0000-associated-type-bounds.md b/text/2289-associated-type-bounds.md similarity index 97% rename from text/0000-associated-type-bounds.md rename to text/2289-associated-type-bounds.md index 3c00eb7250d..92a021137cb 100644 --- a/text/0000-associated-type-bounds.md +++ b/text/2289-associated-type-bounds.md @@ -1,7 +1,7 @@ -- Feature Name: associated_type_bounds +- Feature Name: `associated_type_bounds` - Start Date: 2018-01-13 -- RFC PR: (leave this empty) -- Rust Issue: (leave this empty) +- RFC PR: [rust-lang/rfcs#2289](https://github.com/rust-lang/rfcs/pull/2289) +- Rust Issue: [rust-lang/rust#52662](https://github.com/rust-lang/rust/issues/52662) # Summary [summary]: #summary