Generic conversion from newtypes?


#1

Hi all,

am I missing something, or is it currently not possible in Rust to generically convert out from newtypes?

For example, I would like to create a newtype wrapper for some basic underlying types:

struct Newtype<T>(T);

With this, the following compiles just fine:

impl<T> From<T> for Newtype<T> {
    fn from(v: T) -> Self {
        Newtype(v)
    }
}

However, the reverse doesn’t:

impl<T> From<Newtype<T>> for T {
    fn from(v: Newtype<T>) -> Self {
        v.0
    }
}

// error[E0210]: type parameter `T` must be used as the type parameter for some
// local type (e.g. `MyStruct<T>`); 
// only traits defined in the current crate can be implemented for a type parameter

(I’m a bit confused by this error message, because T does parameterize Newtype, but I guess it refers to the from T part.) Given this error message, I thought to resort to using Into instead, but that also doesn’t compile, for a different reason:

impl<T> Into<T> for Newtype<T> {
    fn into(self) -> T {
        self.0
    }    
}

// error[E0119]: conflicting implementations of trait `std::convert::Into<_>`
// for type `Newtype<_>`:
// note: conflicting implementation in crate `core`
//            - impl<T, U> std::convert::Into<U> for T
//             where U: std::convert::From<T>;

This, too, is confusing to me, because where U: std::convert::From<T> should not apply (?).

[Playground]

As an aside, specializing on the type parameter for From does compile:

impl From<Newtype<i32>> for i32 {
    fn from(v: Newtype<i32>) -> Self {
        v.0
    }
}

In short, is there no generic way to convert out of a newtype, other than using a macro, explicitly instantiating for every single type?


#2

http://smallcultfollowing.com/babysteps/blog/2015/01/14/little-orphan-impls/ talks about things like this in great depth.

There’s a blanket impl<T> From<T> for T in std. There’s also the impl<T, U> Into<U> for T where U: From<T> impl there, which the error message mentions. So if T=U, then you have a conflict.

For a basic wrapper like Newtype<T>(T) I’m afraid not.


#3

While there is no generic way, I think the current convention is to impl an into_inner(self) -> T method for Newtype<T>.


#4

Thanks for the feedback, both! :slight_smile:

Right, I forgot about that. I guess I can only hope that something like the complementary trait RFC gets implemented.

Too bad. :frowning: But I guess that’s how it is.