Help with not satisfied Trait with Box and dyn

Hi,

I'm trying to understand a bit more how boxed traits work and I have a case where I can't figure out why the compiler says the trait isn't satisfied :

#[derive(Default)]
pub struct World {
    pub(crate) storages: HashMap<usize, Box<dyn MyTrait<dyn Any + 'static>>>,
}


pub(crate) trait MyTrait<T: Any + 'static> {
    fn set_component(&mut self, comp: T);
}

pub struct MyImpl<T: Any + 'static> {
    pub(crate) storage: Vec<T>
}

impl <T: Any + 'static> MyTrait<T> for MyImpl<T> {
    fn set_component(&mut self, c: T) {

    }
}

pub fn createImpl<T: Any + 'static>() -> MyImpl<T> {
    MyImpl{
        storage: Vec::<T>::with_capacity(1)
    }
}

pub fn main(){
    let w = World::default();
    let s1 = createImpl::<bool>();
    w.storages.insert(1, Box::new(s1));
}

On the playground here

The compiler says that the trait MyTrait<(dyn Any + 'static)> is not implemented for MyImpl<bool>
But I implemented it with

impl <T: Any + 'static> MyTrait<T> for MyImpl<T>

Can someone help me understand why ? And maybe point me in the right direction ?
Thank you !

This:

impl <T: Any + 'static> MyTrait<T> for MyImpl<T> {

can't work for MyTrait<dyn Any + 'static>, because it would require set_component(&mut self, c: dyn Any) to exist, and it's not possible to pass dyn Trait as an argument. It has to be &dyn Trait or Box<dyn Trait> or some other indirection. This is because dyn implementation can take anything between 0 and 9223372036854775808 bytes, and the compiler doesn't know how many bytes to reserve on stack for that argument (it could vary — dynamically). It does know how many to reserve for a pointer to it.

Same applies to Vec<T> when T is dyn — it's logically not possible to store a vector of same-sized items when each item could dynamically be a different thing with a different size.

I think you're trying to be too generic, even generic over whether the code is generic. Dynamic dispatch is going to require indirection, but monomorphic generics don't need it and work better without it. You're going to have like three layers of abstraction that do nothing except configure which abstractions your abstraction abstracts over…

I suggest make up your mind where you want dynamic dispatch, and hardcode this decision.

2 Likes

A few other observations:

  • You implemented MyTrait<T> for MyImpl<T>, but you never implemented anything else such as MyTrait<dyn Any> for MyImpl<T> where T: Any + 'static.
    So ignoring the rest, you couldn't get a dyn MyTrait<dyn Any> out of a MyImpl<bool>.

    • Note that T: Trait and U: Other<dyn Trait> does not imply U: Other<T>, or any permutation thereof. The only subtyping Rust has is related to lifetimes, not traits or dyn Traits.
  • Your implementation also has the implicit Sized bound on T, so you didn't implement MyImpl<dyn Any> for dyn Any either (dyn Traits are not Sized).

  • If you try to, it blows up due to the Sized requirements on set_component

2 Likes