Implementing Trait for Trait


#1

Hey there!

I hope someone can help me out with this problem. Basically I am trying to implement a trait X for every type T which also implements trait Y.

I do it like that:

impl<T: Y> X for T {}

It works, but when I try to implement the trait std::fmt::Display for my all types implementing my trait, then I get an error:

error[E0119]: conflicting implementations of trait std::fmt::Display for type &_

Playground example: https://play.rust-lang.org/?gist=9a07f9462c120f1f1c47f5abb48d2040&version=stable

I hope someone can point out, what I am doing wrong.


#2

Well, you can’t do that because of coherence. Coherence means an implementation of a given trait for a given type must be unique. In your example, you provide a Display implementation for every type implementing MyError. However, Display is not under your control, as it is part of the standard library. In fact, there are already tons of implementations of it.

Now, suppose you implement MyError for a type that implements Display itself. How should the compiler know, which implementation to pick, when you call the method?

This is why there is the concept of coherence. There are some languages that work around this in different ways. In Rust, you are stuck with this limitation though.

Practically, it does not seem like your MyError trait adds any more value than Display does on its own. So I would simply suggest to get rid of it and use the standard library’s abstraction directly. If you want to go through with the current approach, you need to use some kind of wrapper type, on which you can implement Display. Since you have control over the wrapper, coherence does not apply in that case.


#3

Thanks :smiley:.

Actually I already got rid of the Display impl, but I was still interested, why it actually failed.

Still I find the error message especially confusing. I already guessed something in this direction, but I can still not see on which type the conflict actually occurs. The compiler says &_, which I find confusing.


#4

Isn’t the common workaround to implement the trait on a newtype?


#5

actually you can impl Display for MyError directly without a wrapper
playground


#6

wait, you implemented a trait directly on a trait? I’ve never seen this before, is it documented somewhere?


#7

Not sure where it’s documented but when you define a trait the compiler generates a “companion” trait object by the same name. That’s what allows you to define inherent methods on trait objects of that trait type, ie:

trait Foo {}
impl Foo {
   fn bar(&self) { ... }
}

Now bar is available on all Foo trait objects (eg &Foo, Box<Foo>).

Similarly, you can implement traits for this trait object.