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:
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.
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.
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: