Is there a way to get around `conflicting implementation`? Or to override a trait implemented for a `dyn X`?

I'm trying to hold a bunch of trait objects of type Box<dyn Note> in a vector, and call a method render() on them. The render() method belongs to another trait Renderable.

Although I've implemented Renderable for all of my structs that also implement Note, that isn't sufficient to convince rust that everything that implements Note is also Renderable.

How do I get around this?

I've reduced it to the following minimal example..


I basically want the line generic.render(); to work, and to print "render from Example"

trait Note {}

trait Renderable {
    fn render(&self);
}

struct Example;
impl Note for Example{}
impl Renderable for Example {
    fn render(&self) {
        println!("render from Example");
    }
}


fn main() {
    let concrete: Box<Example> = Box::new(Example{});
    concrete.render();

    let generic: Box<dyn Note> = Box::new(Example{});
    // generic.render();       // I want this line to work
}

For this, I tried the following

impl Renderable for dyn Note {
    fn render(&self) {
        println!("render from dyn Note");
    }
}

If I do this, the generic.render() prints "render from dyn Note" instead of "render from Example".

Alternatively, if I do this

impl<T: Note> Renderable for T {
    fn render(&self) {
        println!("render from T");
    }
}

Then rust tells me that there are conflicting implementations

error[E0119]: conflicting implementations of trait `Renderable` for type `Example`:
  --> src/main.rs:31:1
   |
9  | impl Renderable for Example {
   | --------------------------- first implementation here
...
31 | impl<T: Note> Renderable for T {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Example`

You can make a Renderable a prerequisite for implementing Note like this:

trait Note: Renderable {}

The compiler will then prevent you from implementing Note for anything that doesn’t also implement Renderable and allow you to call Renderable’s methods on all Notes, including dyn Note (and Box<dyn Note> via Box’s Deref implementation).

Yes. Unfortunately, the trait Note lies in a different crate, and adding Renderable to Note would cause me to move a lot of code.

I think I've found a workaround..

trait Note {}
trait Renderable {
    fn render(&self);
}


struct Example;
impl Note for Example{}


trait RenderableNote: Note + Renderable {}

impl RenderableNote for Example {}
impl Renderable for Example{
    fn render(&self) {
        println!("render from Example");
    }
}


fn main() {
    let concrete: Box<Example> = Box::new(Example{});
    concrete.render();

    let generic: Box<dyn RenderableNote> = Box::new(Example{});
    generic.render();       // I want this line to work
}
1 Like

You should also be able to do this:

trait RenderableNote: Note + Renderable {}
impl<T> RenderableNote for T where T: Note + Renderable {}
2 Likes

Oh nice.. that will save me from manually implementing RenderableNote for every Note I make.
Thanks!

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.