Impl dyn Trait + '_ vs extension traits

I've come across this pattern a few times in e.g. the futures crate:

trait MyTrait { ... }
trait MyTraitExt: MyTrait { 
   pub fn some_extension(self) { ... }
}
impl<T: MyTrait> MyTraitExt for T {}

In what ways is this different to the following?

impl dyn MyTrait + '_ {
   pub fn some_extension(self) { ... }
}

The extension trait will be monomorphized, i.e. a copy will be generated for each type it is used with. This generally means faster code, because the compiler can see the definition of the functions in MyTrait that it calls. However more code generated (which can bloat the executable). It is generally considered the preferred way, though that doesn't necessarily mean it's better. Also it works for non-object safe traits and methods, for example your fn some_extension(self) cannot be written with impl dyn MyTrait + '_ because it takes self, which requires Self: Sized but dyn MyTrait + '_ is not Sized.

2 Likes

I can't tell if you have this misunderstanding or not, but also note that implementing a method on dyn Trait + '_ doesn't implement the method for all T: Trait. Additionally, coercion from a base type to dyn Trait doesn't happen as part of method resolution:

trait Trait {}
trait TraitExt: Trait {
    fn trait_ext_method(&self) {}
}

impl dyn Trait + '_ {
    fn dyn_trait_method(&self) {}
}

struct S;
impl Trait for S {}
impl TraitExt for S {}

fn main() {
    let some_struct = S;
    // Works
    some_struct.trait_ext_method();
    // Works
    (&some_struct as &dyn Trait).dyn_trait_method();
    // Fails
    some_struct.dyn_trait_method();
}
1 Like