Help making this code compile

impl<T, E1, E2: From<E1>> From<Result<T, Vec<E1>>> for Result<T, Vec<E2>> {
    fn from(_: Result<T, Vec<E1>>) -> Self {
        todo!()
    }
}

Is there anyway to make something like this compile? I am okay with defining a wrapper MyVec, but it seems to do nothing.

I am also okay with defining a wrapper MyResult IF it can work with ? (but that, if possible, if non-obvious to me).

There is a rule in Rust that says that you can:

  • Implement traits defined in your crate on types from your crate
  • Implement traits defined in your crate on types from another crate
  • Implement traits defined in another crate on types from your crate

This means that you cannot implement traits defined in another crate on types defined in another trait.
So my advice would be to simply define a function that performs the conversion you want.
Also, a side comment - you want to convert from a Result<T, Vec<E1>> to a Result<T, Vec<E2>>. Which means you are probably transforming the error type (I assume). This is precisely the task performed by map_err method on Result.

pub struct MyErr<C, E> {
    stack: Vec<C>,
    err: E,
}

impl<C0, C1: From<C0>, E0, E1: From<E0>> From<MyErr<C0, E0>> for MyErr<C1, E1> {
    fn from(_: MyErr<C0, E0>) -> Self {
        todo!()
    }
}

^-- why am I not allowed to define the above then MyErr is a struct defined in my crate.

The error indicates that the conflict is with an impl for this in the std/core library:

[rustc E0119] [E] conflicting implementations of trait `std::convert::         
   From<MyErr<_, _>>` for type `MyErr<_, _>`                                      
   conflicting implementation in crate `core`:                                    
   - impl<T> From<T> for T;

(It would save time if you include the error message when reporting problems.)

What is the fix to this ?

I think the error is saying that impl<T> From<T> for T already implements the conversion. I'm guessing that the orphan rule (described by @RedDocMD above) restricts you from implementing this conversion because the type parameters you're specifying are completely general, so you're not providing a more specific implementation than the one that is already defined.

Just a guess after playing around with this for a while. But it seems confirmed by the fact that this implementation with specific type params is accepted:

    impl From<MyErr<u16, u32>> for MyErr<u64, u64> {
        fn from(f: MyErr<u16, u32>) -> Self {
            MyErr {
                stack: f.stack.iter().copied().map(Into::into).collect(),
                err: f.err.into(),
            }
        }
    }

Someone else with more experience in this area should probably confirm.

Edit: See next post by @quinedot, the problem is not the orphan rules as I stated above.

In your examples, it's possible to assign type variables such that you're implementing, e.g.

impl From<MyErr<A, B>> for MyErr<A, B> { /* ... */ }

Which conflicts with the blanket implementation mentioned

impl From<T> for T { /* ... */ }

And coherence says you can only ever have one implementation (until we get specialization which says instead it must be unambiguous), hence, the error.

Coherence is also why adding a blanket implementation over your own trait is a breaking change. It's not the orphan rules in the example above, where you own the type.


You can use a custom trait instead.

pub trait MyFrom<T> {
    fn my_from(t: T) -> Self;
}

impl<C0, C1: From<C0>, E0, E1: From<E0>> MyFrom<Result<C0, E0>> for Result<C1, E1> {
    fn my_from(r: Result<C0, E0>) -> Self {
        r.map(Into::into).map_err(Into::into)
    }
}

If you add the corresponding blanket implementation, you'll get a coherence error again:

impl<T> MyFrom<T> for T { fn my_from(_: T) -> Self { todo!() } }
2 Likes

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.