Conflicting implementations of trait `Into<Vec3<_>>` for type `Vec3<_>`

Hi! I'm making my own implementation of a Vec3 type, but I'm currently stuck on converting Vec3<T> into Vec3<O>. I have this code (MRE):

#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub struct Vec3<T> {
    pub x: T,
    pub y: T,
    pub z: T,
}

impl<T: Into<O>, O: From<T>> Into<Vec3<O>> for Vec3<T> {
    fn into(self) -> Vec3<O> {
        let r: Vec3<O> = Vec3::<O> {
            x: self.x.into(),
            y: self.y.into(),
            z: self.z.into()
        };
        r
    }
}

but I get this error:

error[E0119]: conflicting implementations of trait `std::convert::Into<math::vec::Vec3<_>>` for type `math::vec::Vec3<_>`
  --> src/math/vec.rs:58:1
   |
58 | impl<T: Into<O>, O: From<T>> Into<Vec3<O>> for Vec3<T> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: conflicting implementation in crate `core`:
           - impl<T, U> std::convert::Into<U> for T
             where U: std::convert::From<T>;

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

and I kinda get why this is happening, but on the other hand there aren't any other (user-specified, I don't know if the compiler makes one automatically) implementations for Into<Vec3<_>>. Why is this happening, and how can I fix it?

First, instead of implementing Into, you should implement From. From the Into docs:

One should avoid implementing Into and implement From instead. Implementing From automatically provides one with an implementation of Into thanks to the blanket implementation in the standard library.

But that won't fix your problem either, as both From and Into have blanket implementations inside of the standard library that collide with your implementation. I.e., lets say you were implementing From for your Vec3 instead:

#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub struct Vec3<T> {
    pub x: T,
    pub y: T,
    pub z: T,
}

impl<T, O: From<T>> From<Vec3<T>> for Vec3<O> {
    fn from(other: Vec3<T>) -> Self {
        Self {
            x: O::from(other.x),
            y: O::from(other.y),
            z: O::from(other.z),
        }
    }
}

Playground.

Then we have the additional implementation

impl<T> From<T> for T {
    fn from(t: T) -> T {
        t
    }
}

from the standard library as well. Now we want to convert Vec<u32> to Vec<u32>. The compiler wouldn't know whether it should use your implementation or the one from the standard library. Because of that potential conflict, you get your compile error.

Specialization (the feature that should allow resolving such conflicts) won't be a usable part of Rust any time soon, so if you want to keep a generic implementation for your conversions, you should use your own conversion trait (that doesn't have a colliding blanket implementation), rather than From or Into.

1 Like

Would specialization work in nightly?

No, because neither implementation fully specializes the other. You would need something like the lattice rule to accept this, but it's not implemented yet. I would also suggest against using specialization in nightly as it's a highly incomplete feature with numerous soundness issues.

1 Like

Is there a way to implement something like Vec3<T> * Vec3<O> then?

You could do something like this:

use std::ops::Mul;

#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub struct Vec3<T> {
    pub x: T,
    pub y: T,
    pub z: T,
}

impl<T, U> Mul<Vec3<U>> for Vec3<T>
where
    T: Mul<U>,
{
    type Output = Vec3<<T as Mul<U>>::Output>;

    fn mul(self, rhs: Vec3<U>) -> Self::Output {
        Vec3 {
            x: self.x * rhs.x,
            y: self.y * rhs.y,
            z: self.z * rhs.z,
        }
    }
}

Playground.

Or with your original idea of converting U to T to facilitate multiplication:

use std::ops::Mul;

#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub struct Vec3<T> {
    pub x: T,
    pub y: T,
    pub z: T,
}

impl<T, U> Mul<Vec3<U>> for Vec3<T>
where
    U: Into<T>,
    T: Mul<T>,
{
    type Output = Vec3<<T as Mul<T>>::Output>;

    fn mul(self, rhs: Vec3<U>) -> Self::Output {
        Vec3 {
            x: self.x * rhs.x.into(),
            y: self.y * rhs.y.into(),
            z: self.z * rhs.z.into(),
        }
    }
}

Playground.

impl<T, U> Mul<Vec3<U>> for Vec3<T>
where
    U: Into<T>,
    T: Mul<T>,
{
    type Output = Vec3<<T as Mul<T>>::Output>;

    fn mul(self, rhs: Vec3<U>) -> Self::Output {
        Vec3 {
            x: self.x * rhs.x.into(),
            y: self.y * rhs.y.into(),
            z: self.z * rhs.z.into(),
        }
    }
}

This check would work on something like Vec3<i32> * Vec3<i32>, but fails with Vec3<i32> * Vec3<f64>, because i32 doesn't implement From<f64>. Of course, I could just switch around the components to something like Vec3<f64> * Vec3<i32> but I want to have as much compatability as possible with typing.

The problem with that desire I see is that the result of implementing multiplication with conversion is not commutative. Multiplying a Vec<f64> with a Vec<i32> results in a completely different output than multiplying a Vec<i32> with a Vec<f64>. An alternative to implementing multiplication for your vector with a generic parameter U would be to use a declarative macro to implement Mul for each combination of primitive type, which I assume are the only types you want to support anyway:

use std::ops::Mul;

#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub struct Vec3<T> {
    pub x: T,
    pub y: T,
    pub z: T,
}

macro_rules! mul {
    ($t: ty => $($u: ty),* $(,)?) => {
        $(
            impl Mul<Vec3<$u>> for Vec3<$t> {
                type Output = Vec3<<$t as Mul<$t>>::Output>;
    
                fn mul(self, rhs: Vec3<$u>) -> Self::Output {
                    Vec3 {
                        x: self.x * rhs.x as $t,
                        y: self.y * rhs.y as $t,
                        z: self.z * rhs.z as $t,
                    }
                }
            }
        )*
    }
}

mul!(i32 => f64, f32, i8, i16, i32, i64, i128);
mul!(f64 => f64, f32, i8, i16, i32, i64, i128);

fn main() {
    let v1 = Vec3::<i32> { x: 1, y: 2, z: 3 };

    let v2 = Vec3::<f64> {
        x: 1.,
        y: 2.,
        z: 3.,
    };

    println!("{:?}", v1 * v2);
    println!("{:?}", v2 * v1);
}

Playground.

And could this be implemented for other things like Add, Sub, and Div?

Sure.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.