Weaving traits and E0119 (conflicting implementation)

I'm trying to do something fairly complicated, and I've horrible feeling I'm stumbling into an XY problem. However...

First of all, why does this work:

trait A { }
impl A for f64 { }
// impl A for Vec<f64> { }
    
trait B { }
impl<T> B for T where T: A { }
impl<T> B for Vec<T> where T: A { }

while as soon as I uncomment line 3 I get error E0119? Couldn't a conflicting implementation be added at any time making this code invalid already? I actually want to implement trait B in exactly this way, as it happens, and I'm not planning on adding a conflicting implementation. However, I'd really like to understand with this does work, particularly in light of my actual problem, which follows.

So I have callback that will be used to implement B, and I need to parametrise it to return a T or Vec<T> as appropriate. To do this I have been trying to implement a helper trait to interface to the data source; here is a reduced form of what I'm trying to do (here AF64 is one of several sources of f64 data):

trait A {
    type R;
    fn get(&self) -> Self::R;
    fn get_vec(&self) -> Vec<Self::R>;
}

trait C<T: A> {
    fn get_it(&T) -> Self;
}

impl<T> C<T> for T::R where T: A {
    fn get_it(t: &T) -> Self { t.get() }
}

impl<T> C<T> for Vec<T::R> where T: A {
    fn get_it(t: &T) -> Self { t.get_vec() }
}

So I want two implementations of my helper trait C, one for getting a raw value out of an A, and one for getting a vector. I could just throw up my hands and get a vector in the scalar case and throw the vector away, but I'd rather not.

The problem is, of course:

error[E0119]: conflicting implementations of trait `C<_>` for type `std::vec::Vec<_>`:
  --> test.rs:21:1
   |
11 | impl<T> C<T> for T::R where T: A {
   | -------------------------------- first implementation here
...
15 | impl<T> C<T> for Vec<T::R> where T: A {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `std::vec::Vec<_>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0119`.

Ach. I've got a lot of freedom about how to structure this, but I'm going to have a lot of instances of trait A, with several different implementations for each R.

I'm digging myself into a hole here, I'd be grateful for a bit of guidance about what is and isn't actually possible with traits, and whether what I'm doing is actually completely misguided...

Edit: Removed unnecessary impl for A from second part.

If you try to add the conflicting impl in the same crate, then you have control of both parts, so this is considered okay. If you try to add it in an external crate, the orphan rules will complain that neither A nor Vec<f64> are defined in the local crate, and refuse to add the impl.

I'm not quite sure what answer you're looking for, but a good keyword is "orphan rules".

Ok, that is an encouraging reply. However, it only answers the first part of my question, to the effect that what I'm trying to do ought to be possible.

So I'm sort of trying to imitate this pattern in the more complex second half, and am hoping there's a way to express what I'm trying to do in a way that tells the compiler "honest, there aren't conflicting implementations" ... but I can't figure it out, and I guess I haven't explained myself clearly enough.

After all, the second half is just a (more complex) reprise of the (working part of the) first half, so morally "ought" to work.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.