Providing generic implementations of traits for generic classes of types


#1

I have a situation similar to the one in this example, where two generic implementations for classes of types that are meant to be disjoint intersect:

trait Types {
    type A;
    type B;
}

trait MyTrait: Types {
    fn transform(&self, a: Self::A) -> Self::B;
}

trait DelegateMyTrait {
    type Delegate: MyTrait;
    
    fn delegate(&self) -> &Self::Delegate;
}

impl<T: DelegateMyTrait> Types for T {
    type A = <T::Delegate as Types>::A;
    type B = <T::Delegate as Types>::B;
}

impl<T: DelegateMyTrait> MyTrait for T {
    fn transform(&self, a: Self::A) -> Self::B {
        self.delegate().transform(a)
    }
}

impl<T> MyTrait for T
where
    T: Types<A = <T as Types>::B>,
{
    fn transform(&self, a: Self::A) -> Self::B {
        a
    }
}

Is there some technique that would allow me to avoid separate implementations for each T: Types<A = <T as Types>::B>?


#2

I’m a little confused about what disjoint intersect means, seems contradictory.

The two impls are not disjoint, in the example below, Foo would satisfy both impl bounds

struct Foo;
struct Bar;

impl DelegateMyTrait {
    type Delegate = Bar;

    fn foo(&self) -> &Self::Delegate { &Bar }
}

impl Types for Bar {
    type A = ();
    type B = ();
}

impl MyTrait for Bar {
    fn transform(&self, a: Self::A) -> Self::B { () }
}

impl Types for Foo {
    type A = ();
    type B = ();
}

Unfortunately the fix for this is specialization which has been in nightly for a while, and not only that but a feature of it called the lattice rule. The lattice rule isn’t part of the main RFC and will probably require an additional RFC to go through.