Conflicting implementation for impl From<T>, despite bounds

#1

Hi folks,

I’m new to rust and try to implement std::convert::From to convert amongst all instances of my generic type MyType<T>, i.e. MyType<u32> to MyType<f32> to MyType<f64> and so on. The From implementation should be as generic as possible. I know there are pitfalls, so I tried a less generic variant. I also put bounds on the From<OTHER> impls, which in my understanding ensure that OTHER is a distinct type for each impl, but still get conflicting implementation errors.

Could you help me to understand why rustc suspects conflicting implementation for WrappedX<f64>?

Here’s simplified code to reproduce my issue:

use std::convert::From;

trait GetX
{
    type Output; // associated type, i.e. there can only be one impl per Self
    fn x(&self) -> Self::Output;
}

// A simple generic type
struct MyType<T>(T);

impl<T> GetX for MyType<T> where T: Copy
{
    type Output = T;
    fn x(&self) -> Self::Output { self.0 }
}

// Construct a MyType<f64> from any f32 providing type.
impl<OTHER> From<OTHER> for MyType<f64> where OTHER: GetX<Output=f32>
{
    fn from(item: OTHER) -> Self { MyType{0: item.x() as f64 } }
}

// Construct a MyType<f64> from any u32 providing type.
// Compiler says this conflicts with the above impl.
// Why? OTHER is ensured to be distinct by bounds,
// because associated type GetX::Output ensures there's only one GetX impl per type.
impl<OTHER> From<OTHER> for MyType<f64> where OTHER: GetX<Output=u32>
{
    fn from(item: OTHER) -> Self { MyType{0: item.x() as f64 } }
}
#2

This is a known limitation with coherence (overlap checking), whereby associated type bounds don’t play a role in overlap checks.

#3

Wow, thanks for your quick response! Any idea how to solve the problem in a DRY way? There’s a common GetX trait, and the as cast for arithmetic primitive types. It should be possible to leverage these commonalities to avoid duplicated code. The only specific thing is construction of MyType1<T>, …, MyTypeN<T>.

Worst case would be to explicitly write an impl From for each combination of concrete types. Macros may be a bit better, but still seem an ignoble approach for a language like Rust.

#4

To be honest, I’d probably reach for a macro and use it to generate the required impls - I think that’s the clearest and most straightforward workaround.