Use Associated Type From<Self> trait in default impl

The following MVE doesn't compile:

struct Left(usize);
struct Middle(usize);
struct Right(usize);

impl From<Middle> for Right {
    fn from(m: Middle) -> Self {
        Self(m.0)
    }
}
impl From<Middle> for Left {
    fn from(m: Middle) -> Self {
        Self(m.0)
    }
}

trait Autoconvert : std::marker::Sized {
    type LeftType: From<Self>;
    type RightType: From<Self>;
    
    fn default_convert(left: Self::LeftType) -> Self::RightType {
        Self::RightType::from(Self::from(left))
    }
}

impl Autoconvert for Middle {
    type LeftType = Left;
    type RightType = Right;
}

(Playground)

It raises the following exception:

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/lib.rs:21:42
   |
21 |         Self::RightType::from(Self::from(left))
   |                                          ^^^^ expected type parameter `Self`, found associated type
   |
   = note: expected type parameter `Self`
             found associated type `<Self as Autoconvert>::LeftType`
   = note: you might be missing a type parameter or trait bound

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground`.

Is there any way to use an associated type's from trait to perform this Self::from conversion?

Outside of this MVE, I have two wrapper types that I convert to a common middle-man type, I'd rather not have to define another From trait just to be able to perform this trivial from conversion. (And it doesn't seem necessary.)

You've specified that you cat convert Self to Self::LeftType, but trying to go in the opposite way. You probably want type LeftType: Into<Self>, not From.

Seems to be the solution thanks. I wonder why Into<Middle> is not implemented automatically. I was under the impression From<Middle> automatically generated an implementation for Into due to reflexivity.

Updated example, (which requires an implementation of Into):

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ead9aa671b25d9d6bea3a3d41b1c5433

Ahh, I see the reflexsivity went in reverse of what I thought:

From<T> for U implies Into<U> for T

https://doc.rust-lang.org/std/convert/trait.Into.html

Of course. If T is convertible to U, that doesn't mean that U is convertible to T too - the simplest example being integer numbers: u32: From<u16> trivially, but u32 is not Into<u16>, since this would be lossy conversion.

1 Like

Is there a need for a trait that makes both the "to-" and "from-" conversion between two types? It seems clumsy to express this with two From or two Into requirements.

I think something like that would be particularly helpful for wrapper types.

A library I'm working on exports a bunch of Iterators that are simply a wrapper struct around a general purpose iterator. Since each of these wrapper structs
wrap the same object they should all be able to easily cast to and from one another (as well as the object they wrap). It'd be nice if [#repr(transparent)] + some derive did something like this for you automatically.

https://gitlab.com/ertos/fdt-rs/-/blob/5dce88bca7f80f3b2c3572a5995c796119167c61/src/common/iter.rs#154

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.