@@ -178,23 +178,26 @@ With today's `trait_alias`, it wouldn't make much difference for `downstream`.
178
178
179
179
## Splitting a trait
180
180
181
- Consider this humble library:
181
+ To exemplify this use-case, we will use [ Niko Matsakis’s proposal to split the
182
+ ` Deref `
183
+ trait] ( https://github.com/rust-lang/rust/pull/135881#issuecomment-2718417230 ) .
184
+
185
+ ` Deref ` currently looks like this:
182
186
183
187
``` rust
184
- trait Frob {
185
- fn frazzle (& self );
186
- fn brop (& self );
188
+ pub trait Deref {
189
+ type Target : ? Sized ;
190
+
191
+ fn deref (& self ) -> & Self :: Target ;
187
192
}
188
193
```
189
194
190
- Now, let us imagine that the authors of ` frob-lib ` realize that some types can
191
- only implement one of ` frazzle ` or ` brop ` , but not both. They want to split the
192
- trait in two. But, as with our previous example, there is no way to do this in a
193
- backward-compatible way without painful compromises.
195
+ Niko wants to split off the ` type Target ` part into a separate ` Receiver `
196
+ supertrait. But there is no backward-compatible way to do this at present.
194
197
195
198
## Removing a ` Sized ` bound
196
199
197
- Consider this other humble library:
200
+ Consider this humble library:
198
201
199
202
``` rust
200
203
trait Frob {
@@ -205,8 +208,8 @@ trait Frob {
205
208
```
206
209
207
210
Currently, ` Frob::Frobber ` has a ` Sized ` bound, but the signature of ` frob() `
208
- doesn't require it. However, there is no good way at present for ` frob-lib ` to
209
- remove the bound.
211
+ doesn't require it. However, there is no backward-compatible way at present for
212
+ ` frob-lib ` to remove the bound.
210
213
211
214
## Renaming trait items
212
215
@@ -353,6 +356,22 @@ impls for the two underlying traits. Or, alternatively, you can give the trait
353
356
alias a body, and define item aliases with distinct names for each of the
354
357
conflicting items.
355
358
359
+ We can use this to split the ` Deref ` trait, as suggested in the motivation section:
360
+
361
+ ``` rust
362
+ // ! New `Deref`
363
+
364
+ pub trait Reciever {
365
+ type Target : ? Sized ;
366
+ }
367
+
368
+ pub trait DerefToTarget : Reciever {
369
+ fn deref (& self ) -> & Self :: Target ;
370
+ }
371
+
372
+ pub trait Deref = Receiver + DerefToTarget ;
373
+ ```
374
+
356
375
# Reference-level explanation
357
376
358
377
## Implementing trait aliases
@@ -418,8 +437,8 @@ impl IntIterator for Baz {
418
437
// The alias constrains `Self::Item` to `i32`, so we don't need to specify it
419
438
// (though we are allowed to do so if desired).
420
439
421
- fn next (& mut self ) -> i32 {
422
- - 27
440
+ fn next (& mut self ) -> Option < i32 > {
441
+ Some ( - 27 )
423
442
}
424
443
}
425
444
```
@@ -440,8 +459,8 @@ impl IntIterator for Baz {
440
459
// so `Item` must be `i32`
441
460
// and we don't need to specify it.
442
461
443
- fn next (& mut self ) -> i32 {
444
- - 27
462
+ fn next (& mut self ) -> Option < i32 > {
463
+ Some ( - 27 )
445
464
}
446
465
}
447
466
```
@@ -494,7 +513,7 @@ trait IntIter = Iterator<Item = u32> where Self: Clone;
494
513
let iter = [1_u32 ]. into_iter ();
495
514
let _ : IntIter :: Item = IntIter :: next (& mut iter ); // works
496
515
let _ : <array :: IntoIter as IntIter >:: Item = <array :: IntoIter as IntIter >:: next (); // works
497
- // IntIter::clone(&iter); // ERROR: trait `Iterator` has no method named `clone()`
516
+ IntIter :: clone (& iter );
498
517
let dyn_iter : & mut dyn Iterator <Item = u32 > = & mut iter ;
499
518
// IntIter::next(dyn_iter); // ERROR: `dyn Iterator<Item = u32>` does not implement `Clone`
500
519
let signed_iter = [1_i32 ]. into_iter ();
@@ -763,6 +782,64 @@ This is similar to defining an extension trait like
763
782
(One difference from extension traits is that trait aliases do not create their
764
783
own ` dyn ` types.)
765
784
785
+ ## Interaction with ` dyn `
786
+
787
+ Trait aliases do not define their own ` dyn ` types. This RFC does not change that
788
+ pre-existing behavior. However, we do make one change to which trait aliases
789
+ also define a type alias for a trait object. If a trait alias contains multiple
790
+ non-auto traits (primary or not), but one of them is a subtrait of all the
791
+ others, then the corresponding ` dyn ` type for that trait alias is now an alias
792
+ for the ` dyn ` type for that subtrait.
793
+
794
+ This is necessary to support the ` Deref ` example from earlier.
795
+
796
+ ``` rust
797
+ trait Foo {
798
+ fn foo (& self );
799
+ }
800
+ trait Bar : Foo {
801
+ fn bar (& self );
802
+ }
803
+
804
+ trait FooBar = Foo + Bar ; // `dyn FooBar` is an alias of `dyn Bar`
805
+ trait FooBar2 = Foo
806
+ where
807
+ Self : Bar ; // `dyn FooBar2` is also an alias of `dyn Bar`
808
+ ```
809
+
810
+ N.B.: when using implementable trait aliases to split a trait into two parts
811
+ * without* a supertrait/subtrait relationship between them, you have to be
812
+ careful in order to preserve ` dyn ` compatiblilty.
813
+
814
+ ``` rust
815
+ trait Foo {
816
+ fn foo (& self );
817
+ }
818
+ trait Bar {
819
+ fn bar (& self );
820
+ }
821
+
822
+ trait FooBar = Foo + Bar ; // `dyn FooBar` is not a valid type!
823
+ ```
824
+
825
+ To make it work, you can do:
826
+
827
+ ``` rust
828
+ trait Foo {
829
+ fn foo (& self );
830
+ }
831
+
832
+ trait Bar {
833
+ fn bar (& self );
834
+ }
835
+
836
+ #[doc(hidden)]
837
+ trait FooBarDyn : Foo + Bar {}
838
+ impl <T : Foo + Bar + ? Sized > FooBarDyn for T {}
839
+
840
+ trait FooBar = Foo + Bar + FooBarDyn ; // `dyn FooBar` now works just fine
841
+ ```
842
+
766
843
# Drawbacks
767
844
768
845
- The fact that ` trait Foo = Bar + Send; ` means something different than `trait
@@ -786,6 +863,10 @@ complexity of the feature. However, it would also reduce its power: trait
786
863
aliases could no longer be used to rename trait items, and naming conflicts in
787
864
multi-primary-trait aliases would be impossible to resolve.
788
865
866
+ It's this last issue especially that leads me to not relegate this to a future
867
+ possibility. Adding a defaulted item to a trait should at most require minor
868
+ changes to dependents, and restructuring a large ` impl ` block is not “minor”.
869
+
789
870
## No non-implementable items in trait alias bodies
790
871
791
872
Such items don't have much utility from a backward-compatibility perspective,
@@ -830,7 +911,8 @@ even at the risk of potential confusion.
830
911
831
912
## Allow ` impl Foo + Bar for Type { ... } ` directly, without an alias
832
913
833
- It's a forward-compatibility hazard, with no use-case that I can see.
914
+ It's a forward-compatibility hazard (if the traits gain items with conflicting
915
+ names), with no use-case that I can see.
834
916
835
917
## Implementing aliases with 0 primary traits
836
918
@@ -851,9 +933,23 @@ I don't see the point in it.
851
933
make this feature more powerful as well.
852
934
- Variance bounds could allow this feature to support backward-compatible
853
935
GATification.
854
- - ` trait Foo: Copy = Iterator; ` could be allowed as an alternative syntax to
855
- ` trait Foo = Iterator where Self: Copy; ` .
856
936
- We could allow trait aliases to define their own defaults for ` impl ` s. One
857
937
possibility is [ the ` default partial impl ` syntax I suggested on
858
938
IRLO] ( https://internals.rust-lang.org/t/idea-partial-impls/22706/ ) .
859
939
- We could allow implementable ` fn ` aliases in non-alias ` trait ` definitions.
940
+ - We could allow any ` impl ` block to implement items from supertraits of its
941
+ primary trait(s).
942
+ - This would allow splitting a trait into a supertrait and a subtrait without
943
+ having to give the subtrait a new name.
944
+ - However, it would make it more difficult to deduce what traits an ` impl `
945
+ block is implementing.
946
+ - In addition, it poses a danger if an ` unsafe ` subtrait depends on an
947
+ ` unsafe ` marker supertrait: you could implement the subtrait, carefully
948
+ checking that you meet its preconditions, while not realizing that you are
949
+ also implementing the supertrait and need to check its conditions as well.
950
+ - And even if the traits are not ` unsafe ` , they could still have preconditions
951
+ that are important for correctness. Users should never be committing to such
952
+ things unknowingly.
953
+ - We could add an attribute for trait aliases to opt in to generating their own
954
+ ` dyn ` type.
955
+ - This could be prototyped as a proc macro.
0 commit comments