Why are these "Conflicting implementations"?


#1

I am getting the following error message from the compiler:

src/lib.rs:126:1: 138:2 error: conflicting implementations of trait `IntoMyFunc<_>`: [E0119]
src/lib.rs:126 impl<T, S: Fn(&MyType) -> Result<MyType>> IntoMyFunc<T> for S {
               ^
src/lib.rs:126:1: 138:2 help: run `rustc --explain E0119` to see a detailed explanation
src/lib.rs:112:1: 124:2 note: conflicting implementation is here:
src/lib.rs:112 impl<T, S: Fn() -> Result<MyType>> IntoMyFunc<T> for S {

I found it surprising because Fn(&MyType) -> Result<MyType> is different from: Fn() -> Result<MyType>


Polymorphism vs. Into Traits
#2

Fn is generic over the argument types. There isn’t anything stopping someone from creating a type which implements both Fn(i32) and Fn(). (This isn’t really set in stone, given that unboxed_closures is still unstable, but that’s how it works at the moment.)

Edit: Err, that’s correct, but not actually relevant; thanks stebalien for the correction.


#3

nit: the fact thta Fn is generic over it’s argument types isn’t really relevant. Two independent triats Foo and Bar would exhibit the same problem.


#4

Well, the fact that Fn is generic over it’s argument types isn’t actually completely irrelevant; consider:

trait A { type Result; }
trait B {}
struct S<T>(T);
impl<T: A<Result=i32>> B for S<T> {}
impl<T: A<Result=u32>> B for S<T> {}

The implementations don’t overlap because it’s impossible for any type to implement both A<Result=i32> and A<Result=u32>.

That said, Rust doesn’t currently allow this; in general, where clauses in impls can’t be used to resolve conflicting implementations.


#5

IntoMyFunc (not the real name :slight_smile: ) is a trait that allows me to wrap functions easily into MyFunc signature. The goal was to allow function with different signatures as input to the same method. Is there any work around to do this? The only way I see is to create many different methods, each accepting a function with a different signature. But it makes the API unnecessarily big.


#6

It’s hard to say what the best way to structure your code is without seeing more of it… but in general, trying to fake overloading is the wrong approach. Maybe some sort of wrapper object which implements your trait would be appropriate.


#7

I did approach this differently at the beginning, namely by creating several functions called wrapping_*. But it was terribly annoying to remember which wrapper to use (there are just to many options and naming is not obvious). I have to conform to a function with 4 inputs and a particular output type. But many cases I just want to use a simple function that returns a String or import and use a function from another project. Using an Into like trait for this particular type of overloading seemed to be good idea as described here and here


#8

I have run into similar problems, and I think wrapping a struct makes the code unnecessarily complex. I think negative trait bounds (with suitable limitations, like only traits defined in the same module can be used negatively) are the best solution to this (if they get implemented).


#9

Is there any reason why Fn(&MyType) -> Result<MyType> is equivalent to Fn() -> Result<MyType>?


#10

They’re not equivalent, they’re just overlapping. There’s just no rule that says you can’t implement both Fn(&MyType) -> Result<MyType> and Fn() -> Result<MyType> for the same type. Remember that Fn(A) -> B is a trait like Iterator or Clone, not a specific type.