-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: Associated type bounds of form MyTrait<AssociatedType: Bounds>
#2289
Merged
Merged
Changes from 1 commit
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
e91e24d
rfc, associated-type-bounds: initial text
Centril 244d5aa
rfc, associated-type-bounds: resolve question on syntax ambiguity.
Centril f279bac
rfc, associated_type_bounds: fix desugaring + other house keeping
Centril d1398b2
Merge pull request #2 from Centril/rfc/associated-type-bounds-patch-1
Centril 95d569a
rfc, associated-type-bounds: clarify a bunch of things / leave some t…
Centril 4682216
rfc, associated-type-bounds: improve grammar + link to RFC 2071 (+ no…
Centril fb31e7e
rfc, associated-type-bounds: phrasing consistency of impl Trait stuff.
Centril 1376723
Merge pull request #4 from Centril/rfc/associated-type-bounds-patch-2
Centril 2a685b5
RFC 2289
Centril File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<AssociatedType: Bounds>`, permitted anywhere | ||
a bound of the form `MyTrait<AssociatedType = T>` would be allowed. This form | ||
desugars to `MyTrait<AssociatedType = impl Bounds>`. | ||
|
||
# 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<AssociatedType = T>`. With the introduction of the `impl Trait` | ||
syntax for static-dispatch existential types, this syntax also permits | ||
`MyTrait<AssociatedType = impl Bounds>`, 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<AssociatedType: Bounds>`. | ||
|
||
# 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<T: Iterator<Item: Display>>(printables: T) { | ||
for p in printables { | ||
println!("{}", p); | ||
} | ||
} | ||
``` | ||
|
||
## In anonymous existential types | ||
|
||
```rust | ||
fn printables() -> impl Iterator<Item: Display> { | ||
// .. | ||
} | ||
``` | ||
|
||
## Further examples | ||
|
||
Instead of writing: | ||
|
||
```rust | ||
impl<I> Clone for Peekable<I> | ||
where | ||
I: Clone + Iterator, | ||
<I as Iterator>::Item: Clone, | ||
{ | ||
// .. | ||
} | ||
``` | ||
|
||
you may write: | ||
|
||
```rust | ||
impl<I> Clone for Peekable<I> | ||
where | ||
I: Clone + Iterator<Item: Clone> | ||
{ | ||
// .. | ||
} | ||
``` | ||
|
||
or replace the `where` clause entirely: | ||
|
||
```rust | ||
impl<I: Clone + Iterator<Item: Clone>> Clone for Peekable<I> { | ||
// .. | ||
} | ||
``` | ||
|
||
# Reference-level explanation | ||
[reference-level-explanation]: #reference-level-explanation | ||
|
||
The surface syntax `Trait<AssociatedType: Bounds>` should desugar to | ||
`Trait<AssociatedType = impl Bounds>` 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<AssociatedType = impl Bounds>` 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? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We were pretty sure that there wouldn't be any - but it is nice to get that confirmed. |
||
- Does allowing this for `dyn` trait objects introduce any unforseen issues? |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure literally desugaring like this will be legal and will mean the same thing in all contexts.
Maybe it's better to use the desugaring from the examples above (
T: Trait<AssocTy: Bounds>
->T: Trait + <T as Trait>::AssocTy: Bounds
) everywhere?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice sugar, overall.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So in other words:
T: Trait<AssocTy: Bounds>
desugars into adding<T as Trait>::AssocTy: Bounds
to the list ofwhere
clauses? How do we deal with that in the case of the following?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Centril
-> impl Iterator<Item = T>
is already desugared to two bounds,X: Iterator
and<X as Iterator>::Item == T
, whereX
is theimpl Iterator<Item = T>
nominal type.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@petrochenkov That's great! It means we can implement this today with very little effort, since we have all the needed infrastructure from
Trait<AssocTy = T>
(assuming we don't even need to handle trait objects).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@petrochenkov You are more familiar with the inner workings of the compiler, so I think you can better specify the proper desugaring. Could you PR against our PR perhaps?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Patch in: Centril#2