Confusing conflicting implementations


#1

I’m trying to get around coherence, and running into conflicting impls! In effect, I want to implement FromStr for Option<MyType>. That goes against the orphan check, so I defined my own local trait MyFromStr, with a blanket impl for types that implement FromStr.

Code is below. I’m a bit confused about how the blanket impl conflicts, as FromStr isn’t defined for Option. What am I missing?

use std::str;

trait MyFromStr: Sized + str::FromStr {
    type Err;
    fn my_from_str(s: &str) -> Result<Self, <Self as MyFromStr>::Err>;
}

impl<T, E> MyFromStr for T
    where T: str::FromStr<Err = E>
{
    type Err = E;
    fn my_from_str(s: &str) -> Result<T, E> {
        str::FromStr::from_str(s)
    }
}

struct MyType;
impl MyFromStr for Option<MyType> {
    type Err = ();
    fn my_from_str(s: &str) -> Result<Self, ()> {
        unimplemented!();
    }
}

playground


#2

Oh. What I’m missing is that FromStr could be defined for Option, which then would conflict. Argh! Is there a way around this kind of issue?


#3

The only way around this is to define a new wrapper type around Option<MyType>. I suspect that might not be workable for you.

There are three conflicting ideal attributes for the trait system:

  • I want the impl found for my type to be deterministic and not to change.
  • I want adding an impl to not be a breaking change for my crate, and I want adding new dependencies to not break my build.
  • I want to be able to define any trait for any type.

Unfortunately we can only have two of these, and Rust chose the first two (Haskell is an example of a language that, as I understand it, chose the first and third).