Rustコトハジメ

プログラミング言語Rustに関する情報をお届けします。

Into to From blanket implementation is not possible

In the previous post

www.rustforbeginners.com

we have confirmed that there is a blanket implementation impl Into for From but there is none for the opposite.

In the post, I explained the reason as impl Into for From is more nice to have than the opposite. But didn't explain why we can't define both. Let's have a small experiment.

To write blanket implementations the traits should be in your crate. However, From and Into is not yours. So Let's define our own traits first and name them Into2 and From2.

trait Into2<T> {
    fn into(self) -> T;
}

trait From2<S> {
    fn from(s: S) -> Self;
}

impl<S, T> Into2<T> for S where T: From2<S> {
    fn into(self) -> T {
        T::from(self)
    }
}

impl<S, T> From2<S> for T where S: Into2<T> {
    fn from(s: S) -> T {
        s.into()
    }
}

struct A {
    x: i32
}
impl Into2<i32> for A {
    fn into(self) -> i32 {
        self.x
    }
}

fn main() {}

When we try to compile this code we get a error:

error[E0119]: conflicting implementations of trait `Into2<i32>` for type `A`:
  --> prog.rs:24:1
   |
9  | impl<S, T> Into2<T> for S where T: From2<S> {
   | ------------------------------------------- first implementation here
...
24 | impl Into2<i32> for A {
   | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A`

The error should be telling us that

  1. We definedInto2<i32> for A.
  2. From2<A> for i32 is automatically defined.
  3. Into2<i32> for A is automatically defined.
  4. The two eventually conflict.

This is why we can't have these two blanket implementations.