rusttraits

Why do blanket implementations for two different traits conflict?


Say I have this code:

pub trait A {}
pub trait B {}

pub trait SomeBehavior {
  fn func() -> bool;
}

And I want to provide the blanket implementation for A and B like this:

impl <T> SomeBehavior for T where T: A {
  fn func() -> bool { true }
}

impl <T> SomeBehavior for T where T: B {
  fn func() -> bool { false }
}

But this gives following error:

error[E0119]: conflicting implementations of trait `SomeBehavior`
  --> src/lib.rs:12:1
   |
8  | impl <T> SomeBehavior for T where T: A {
   | -------------------------------------- first implementation here
...
12 | impl <T> SomeBehavior for T where T: B {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation

Why the compiler treats two different implementations on different traits as same implementation?


Solution

  • Rust has the concept of "trait coherence" which is the idea that for any combination of type and trait there should be at most one implementation of that trait. This is the concept that guides Rust's "orphan rule" and is designed to ensure that conflicting implementations can't occur in downstream crates.

    So the problem with the two blanket implementations above is the possibility that a type can implement both A and B. There would then be two possible implementations for SomeBehavior for that type.

    struct MyType;
    impl A for MyType;
    impl B for MyType;
    
    let t = MyType;
    let _ = t.func(); // how to choose?
    

    Its not particularly well documented part of Rust unfortunately; likely because its complicated, its contentious, the rules have changed over the years, and will likely change again in the future. Resources are scattered between blog posts, RFCs, and issues but you can find the important bits in the Coherence section of the chalk book (the next-generation trait-solver).

    There may be features added in the future that may allow this or something similar: