From<Type<A> for Type<B>

Hi,

I have a simple structure that is generic over the numeric type - but want to easily be able to convert from one underlying type to another. However, trying to implement that I run into E0119. I think after reading around that there is no way for me to implement From/Into for my struct - but wanted too make sure.

Is there any way I in this From implementation can specify that A != B so that II implement it only for non equal types (e.g. f32 and f64) without conflicting with the std implementation?

Playground snippet

regards

AFAIK this is not possibe with today's Rust.

1 Like

Thanks for confirming - that's what I though :frowning:

Will have to be a macro and implement a lot of combinations explicitly.

Thx

Alternatively, you could do something like this:

#[derive(Debug, Clone)]
pub struct Curve<T> {
    pub x: Vec<T>,
    pub y: Vec<T>,
}

impl<T> Curve<T> {
    fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> Curve<U> {
        Curve {
            x: self.x.into_iter().map(&mut f).collect(),
            y: self.y.into_iter().map(&mut f).collect(),
        }
    }
}

fn main() {
    let a = Curve {
        x: vec![1, 2, 3],
        y: vec![4, 5, 6],
    };
    let b: Curve<f64> = a.map(Into::into);
    println!("{b:?}");
}

(Playground)

Output:

Curve { x: [1.0, 2.0, 3.0], y: [4.0, 5.0, 6.0] }

This doesn't get you the From implementation directly on Curve<T>, but will allow you to do all conversions with a slighly more verbose syntax: .map(Into::into) instead of .into().


Or maybe using Fn instead of FnMut if you want to emphasize that the order of processing isn't guaranteed:

 impl<T> Curve<T> {
-    fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> Curve<U> {
+    fn map<U, F: Fn(T) -> U>(self, f: F) -> Curve<U> {
         Curve {
-           x: self.x.into_iter().map(&mut f).collect(),
-           y: self.y.into_iter().map(&mut f).collect(),
+           x: self.x.into_iter().map(&f).collect(),
+           y: self.y.into_iter().map(&f).collect(),
         }
     }
 }

(Playground)

2 Likes

If you want (or need to?) be generic over the outer Type, you could use a functor, which I just implemented in the fmap crate (see long thread here for the genesis).

[dependencies]
fmap = "0.1.0"
use fmap::Functor;

#[derive(Debug, Clone)]
pub struct Curve<T> {
    pub x: Vec<T>,
    pub y: Vec<T>,
}

impl<'a, A, B> Functor<'a, B> for Curve<A>
where
    A: 'a,
    B: 'a,
{
    type Inner = A;
    type Mapped<'b> = Curve<B>
    where
        'a: 'b;
    fn fmap<'b, F>(self, f: F) -> Self::Mapped<'b>
    where
        'a: 'b,
        F: 'b + Fn(Self::Inner) -> B,
    {
        Curve {
            x: self.x.fmap(&f),
            y: self.y.fmap(&f),
        }
    }
}

fn main() {
    let vec_a: Vec<i32> = vec![10, 20, 30, 40];
    let vec_b: Vec<f64> = vec_a.fmap(Into::into);
    println!("{vec_b:?}");

    let curve_a = Curve {
        x: vec![1, 2, 3],
        y: vec![4, 5, 6],
    };
    let curve_b: Curve<f64> = curve_a.fmap(Into::into);
    println!("{curve_b:?}");
}

Output:

[10.0, 20.0, 30.0, 40.0]
Curve { x: [1.0, 2.0, 3.0], y: [4.0, 5.0, 6.0] }

However, this still doesn't implement From on the outer type. You still have to use .fmap(Into::into) on outer types, instead of just .into(). But it is possible to be generic:

fn foo<'a, T, A, B>(curve_or_vec_or_other_functor: T) -> T
where
    T: FunctorSelf<'a, A>,
    A: 'a + Into<B>,
{
    curve_or_vec_or_other_functor.fmap(Into::into)
}

P.S.: But I believe being that generic is non-idiomatic in Rust. Afterall, the standard library also provides all sort of .map methods, which are unrelated (except sharing the same name).

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.