Skip to content

Commit 65657d0

Browse files
committed
rfc, self_in_typedefs: discuss Self in where bounds
1 parent 62153f7 commit 65657d0

File tree

1 file changed

+100
-7
lines changed

1 file changed

+100
-7
lines changed

text/0000-self-in-typedefs.md

Lines changed: 100 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ The special `Self` identifier is now permitted in `struct`, `enum`, and `union`
1010
type definitions. A simple example `struct` is:
1111

1212
```rust
13-
enum List<T> {
13+
enum List<T>
14+
where
15+
Self: PartialOrd<Self> // <-- Notice the `Self` instead of `List<T>`
16+
{
1417
Nil,
15-
Cons(T, Box<Self>) // <-- Notice the `Self` instead of `List<T>`
18+
Cons(T, Box<Self>) // <-- And here.
1619
}
1720
```
1821

@@ -41,9 +44,9 @@ impl Foo<Self> for Quux {
4144
}
4245
```
4346

44-
But this is not currently possible inside type definitions. This makes the
45-
language less consistent with respect to what is allowed in type positions
46-
than what it could be.
47+
But this is not currently possible inside both fields and where clauses of
48+
type definitions. This makes the language less consistent with respect to what
49+
is allowed in type positions than what it could be.
4750

4851
## Principle of least surprise
4952

@@ -190,6 +193,69 @@ struct NonEmptyList<T> {
190193

191194
This also extends to `union`s.
192195

196+
## `where`-clauses
197+
198+
In today's Rust, it is possible to define a type such as:
199+
200+
```rust
201+
struct Foo<T>
202+
where
203+
Foo<T>: SomeTrait
204+
{
205+
// Some fields..
206+
}
207+
```
208+
209+
and with some `impl`s:
210+
211+
```rust
212+
trait SomeTrait { ... }
213+
214+
impl SomeTrait for Foo<u32> { ... }
215+
impl SomeTrait for Foo<String> { ... }
216+
```
217+
218+
this idiom bounds the types that the type parameter `T` can be of but also
219+
avoids defining an `Auxiliary` trait which one bound `T` with as in:
220+
221+
```rust
222+
struct Foo<T: Auxiliary> {
223+
// Some fields..
224+
}
225+
```
226+
227+
You could also have the type on the right hand side of the bound in the `where`
228+
clause as in:
229+
230+
```rust
231+
struct Bar<T>
232+
where
233+
T: PartialEq<Bar<T>>
234+
{
235+
// Some fields..
236+
}
237+
```
238+
239+
with this RFC, you can now redefine `Foo<T>` and `Bar<T>` as:
240+
241+
```rust
242+
struct Foo<T>
243+
where
244+
Self: SomeTrait // <-- Notice `Self`!
245+
{
246+
// Some fields..
247+
}
248+
249+
struct Bar<T>
250+
where
251+
T: PartialEq<Self> // <-- Notice `Self`!
252+
{
253+
// Some fields..
254+
}
255+
```
256+
257+
This makes the bound involving `Self` slightly more clear.
258+
193259
## When `Self` can **not** be used
194260

195261
Consider the following small expression language:
@@ -321,8 +387,10 @@ is the [*"Learning Rust With Entirely Too Many Linked Lists"* guide][LRWETMLL].
321387
# Reference-level explanation
322388
[reference-level-explanation]: #reference-level-explanation
323389

324-
The identifier `Self` is (now) allowed in type contexts in
325-
fields of `struct`s, `union`s, and the variants of `enum`s.
390+
The identifier `Self` is (now) allowed in type contexts in fields of `struct`s,
391+
`union`s, and the variants of `enum`s. The identifier `Self` is also allowed
392+
as the left hand side of a bound in a `where` clause and as a type argument
393+
to a trait bound on the right hand side of a `where` clause.
326394

327395
## Desugaring
328396

@@ -357,6 +425,28 @@ enum StackList<'a, T: 'a + InterestingTrait> {
357425
}
358426
```
359427

428+
An example of `Self` in `where` bounds is:
429+
430+
```rust
431+
struct Foo<T>
432+
where
433+
Self: PartialEq<Self>
434+
{
435+
// Some fields..
436+
}
437+
```
438+
439+
which desugars into:
440+
441+
```rust
442+
struct Foo<T>
443+
where
444+
Foo<T>: PartialEq<Foo<T>>
445+
{
446+
// Some fields..
447+
}
448+
```
449+
360450
[RFC 2102]: https://github.com/rust-lang/rfcs/pull/2102
361451

362452
## In relation to [RFC 2102] and what `Self` refers to.
@@ -595,6 +685,9 @@ some users that `Self` already works, as discussed in the [motivation],
595685
the expectation that this alternative already works has not been brought
596686
forth by anyone as far as this RFC's author is aware.
597687

688+
It is also unclear how internal scoped type aliases would syntactically work
689+
with `where` bounds.
690+
598691
Strictly speaking, this particular alternative is not in conflict with this
599692
RFC in that both can be supported technically. The alternative should be
600693
considered interesting future work, but for now, a more conservative approach

0 commit comments

Comments
 (0)