Giving certain `impl`s priority over others: `error[E0119]: conflicting implementations of trait`

To prevent an XY problem, here's my initial problem:
I have a type T, and want to preform an action based on its type. I learned the best way to do this is with a trait and different impls for the different types, so I did that:

struct A(u8);

impl Into<u8> for A {
    fn into(self) -> u8 {
        self.0
    }
}

trait Printable {
    fn print(self);
}

impl<T: Into<u8>> Printable for T {
    fn print(self) {
        println!("Into {}", self.into());
    }
}

fn main() {
    1.print();
    A(2).print();
}

Now if it's a u8, I want to print "Just {}" instead of "Into {}", so I tried adding this:

impl Printable for u8 {
    fn print(self) {
        println!("Just {}", self);
    }
}

But got this error:

error[E0119]: conflicting implementations of trait `Printable` for type `u8`

Which makes sense, since u8 implements Into<u8>.
How would I achieve that result?

This is called specialization, and it's a hard problem. As of today, you can't generally have a blanket and a non-blanket impl of the same trait.

Can you impl Printable for A only?

1 Like

No, I'm afraid I can't. I really need to check if it implements a certain Into trait.
There's a way to check if the exact type matches:

TypeId::of::<T>() == TypeId::of::<String>()

But that doesn't work with traits (like Into<u8>) does it?

You are not checking that, though – you are creating a blanket impl.

But if you only need the special case for u8, and you can tolerate restricting the set of types to 'static (i.e., owned) ones, then you can use the type ID to check for u8 inside the blanket impl (Playground).

2 Likes

You can do this on nightly but I really wouldn't recommend it. Specialization is something many people on this forum want. But the consensus seems to be that it won't be coming to stable Rust any time soon. The current nightly specialization feature is unsound. In the example I use the min_specialization feature instead, which is sound AFAIK:

#![feature(min_specialization)]

struct A(u8);

impl Into<u8> for A {
    fn into(self) -> u8 {
        self.0
    }
}

trait Printable {
    fn print(self);
}

impl<T: Into<u8>> Printable for T {
    default fn print(self) {
        println!("Into {}", self.into());
    }
}

impl Printable for u8 {
    fn print(self) {
        println!("Just {}", self);
    }
}

fn main() {
    1.print();
    A(2).print();
}

Playground.

2 Likes

I'm not sure with that. I was going to leave an issue here but it seems is fixed two weeks ago. I'm not sure whether there are more holes.

3 Likes

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.