How to type self from trait

Hello,

I have a trait which call a function expecting this trait as parameter. But i don't know how type that. Example:

struct MyStruct1 {

}

impl MyStruct1 {
    fn my_struct_func(&self, obj: Box<dyn MyTrait>) {

    }
}

trait MyTrait {
    fn my_func(&self) {
        let my_struct = MyStruct1 {};
        my_struct.my_struct_func(self);
    }
}

fn main() {}

Produce

error[E0308]: mismatched types
  --> src/main.rs:15:34
   |
15 |         my_struct.my_struct_func(self);
   |                                  ^^^^
   |                                  |
   |                                  expected struct `Box`, found `&Self`
   |                                  help: store this in the heap by calling `Box::new`: `Box::new(self)`
   |
   = note: expected struct `Box<(dyn MyTrait + 'static)>`
           found reference `&Self`
   = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html

I tried some things without success (like my_struct.my_struct_func(&self as Box<dyn MyTrait>); or my_struct.my_struct_func(Box::new(self));).

How to do that ? Thanks in advance :

The basic problem is that MyStruct1::my_struct_func wants a boxed trait object Box<dyn MyTrait>, but MyTrait::my_func takes a shared reference &self. You can fix the mismatch by having MyTrait::my_func take Box<Self> as a receiver, like this:

trait MyTrait {
    fn my_func(self: Box<Self>) where Self: 'static + Sized {
        let my_struct = MyStruct1 {};
        my_struct.my_struct_func(self as Box<dyn MyTrait>);
    }
}

(I'm not quite sure why Self: Sized is needed here...)

It's needed to allow a coercion between Box<Self> and Box<dyn MyTrait>, because unsized types can implement MyTrait, but pointers to unsized types can't (in general) be coerced into pointers to MyTrait

Is this because a pointer to an unsized type is already "fat" and so making it "fatter" by adding the vtable pointer for MyTrait would cause problems?

Right, once you have a trait object it only has a single vtbl: for the trait it represents. You cannot then “discover” another vtbl for some other trait the underlying value may implement.

1 Like

Thanks for your times !

That’s not a complete answer, because non-dyn unsized types, like [u32], are also forbidden from being turned into trait objects. You can also impl TraitB for dyn TraitA, but can’t cast dyn TraitA into dyn TraitB.

The information in the second field of the original fat pointer needs to needs to be stored somewhere, and there’s simply no place for it to go. It can’t be stored on the heap without an allocation. If you add it as a third field to the pointer, then that’s no longer the same layout as &dyn Trait; it would have to be a new type.

2 Likes