2

When extending traits defined in other crates, there seem to be two ways to default implement a new trait.

The original definition of a trait is

pub trait Trait1 {
    fn f1(&self);
}

In order to extend the functionality of this trait, we define a trait Trait2,

pub trait Trait2 {
    fn f2(&self);
}

Now, because we want the functionality to be available by default, we can implement the following

impl<T> Trait2 for T
where
    T: Trait1,
{
    pub fn f2(&self) {
        self.f1()
    }
}

impl Trait2 for dyn Trait1 {
    pub fn f2(&self) {
        self.f1()
    }
}

What I have observed is that, when mixing with trait objects, both of these implementations are required.

I understand that the impl<T> one is for concrete classes where as other is for dyn objects. Is that correct? Is there any way to share the default implementation here for both of these types? In my scenario, I had to copy and paste the whole implementation with just the change of the first line.

trent
  • 25,033
  • 7
  • 51
  • 90
BomberGuy7
  • 23
  • 4
  • 2
    it's a bit unclear what you are asking. Could you edit the post to give a more concrete example? – Peter Hall Oct 27 '20 at 23:26
  • 1
    This is a great first question and thanks for adding code. I just tweaked the formatting to match other [tag:rust] questions, in the hopes that it will be more readable and useful for future users. Welcome to Stack Overflow! – trent Oct 28 '20 at 00:11

1 Answers1

3

If I understood your question correctly, just add the unsized (?Sized) bound to T:

impl<T> Trait2 for T where T: Trait1 + ?Sized

This implements Trait2 for unsized types (eg. dyn Trait1) that implement Trait1 as well. By default, all type parameters are sized, and hence do not match unsized types.

Playground

EvilTak
  • 7,091
  • 27
  • 36
  • 2
    I was writing an answer but you beat me to it so I'll just hijack your comments with links. Feel free to add any of this information to the answer if you feel it belongs. [This question covers why there is a default `Sized` bound on `T`.](/q/28044231/3650362) [This one also seems tangentially relevant.](/q/34438755/3650362) – trent Oct 28 '20 at 00:00
  • 2
    Finally, there is one reason you might need both of the first two `impl`s. [It is not possible to cast an arbitrary `?Sized` type to `dyn Trait1`, even if it implements `Trait1`](/q/57398118/3650362). So if the implementation of `Trait2` requires casting specifically to `dyn Trait1`, it can be written for `dyn Trait1`, and for `T: Trait1`, but *not* for `T: Trait1 + ?Sized`. If that's the case you will be stuck with the two original `impl`s. – trent Oct 28 '20 at 00:00