How to call method implemented for dyn Trait without cast

Hi.
I have two traits A and B<T>, and struct C. C implements B<SomeType> and dyn B<T> implements A.
I can use method of A by (&c as &dyn B<SomeType>).method(), but are there any other way?

That's the only way. &C can be converted to &dyn B<T> just like i32 can be converted to i64.

No, the compiler needs to know what trait object type you're using. C could implement B<SomeType> and B<AnotherType>, and then c.method() would be ambiguous.

Possible alternatives might include making T an associated type like E is, adding a type parameter to C, adding a type parameter to A, or writing a new trait with a type parameter and a blanket impl for U: B<T>. That last one sounds complicated so here's what I mean:

trait Hello<T> {
    type Err;
    fn hello(&self);
}

impl<T, U: 'static + b::B<T>> Hello<T> for U {
    type Err = U::E;
    fn hello(&self) {
        a::A::hello(self as &dyn b::B<T, E = Self::Err>);
    }
}

fn main() {
    let c = c::C {};
    c.hello();  // the compiler can figure out `T` at this point
}

(Note that this relies on there being only one B<?> implemented for C; if you add another B implementation, you'll have to specify which one by writing something like <C as Hello<u8>>::hello(&c).)

For a situation like this, Iā€™d provide an as_a() method on B, and also (more optionally) a struct that can use static dispatch instead of dynamic:

mod b {
    pub trait B<T> {
        type E;
        fn as_a(&'_ self) -> AsA<'_, T, Self> {
            AsA {
                val: self,
                param: std::marker::PhantomData,
            }
        }
    }

    pub struct AsA<'a, T, Inner: 'a + ?Sized> {
        val: &'a Inner,
        param: std::marker::PhantomData<T>,
    }

    impl<'a, T, Inner: B<T> + 'a + ?Sized> crate::a::A for AsA<'a, T, Inner> {}
}

fn main() {
    let c = c::C {};
    c.as_a().hello();
}

(Playground)

1 Like