Into and From for newtype pattern

The question is simple. I have a simple "newtype pattern" type.

pub struct Foo<T> (T);

I want to derive From<T> for it.

impl<T> From<T> for Foo<T> {
  fn from(value: T) -> Self {
    Self(value)
  }
}

So far so good. but what about the other way around? Implementing From<Foo<T>> yields E0210

impl<T> From<Foo<T>> for T {
  fn from(value: Foo<T>) -> Self {
    todo!()
  }
}

and implementing Into<T> for Foo<T> yields E0119

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

saying conflicting implementation in crate core: impl<T, U> Into<U> for T where U: From<T>.

What am I doing wrong? What is this conflict exactly?

The problem is that there's no rule that guarantees an impl like impl<T> From<T> for MyType won't exist, and that impl would conflict with your implementation.

1 Like

Design wise, if your newtype doesn't enforce rules why do you need it? (meaning making one from T cannot fail as From implies)

I don't get that. There are plenty of situations where a newtype can be infallibly created from the wrapped value and its purpose is not to enforce some property of the inner value. For example, a Mutex<T> is From<T>, but you wouldn't say that it serves no purpose. Similarly, I saw a question yesterday, in which OP wanted to implement 3rd-party traits for other 3rd-party types. The solution was to create a newtype wrapper and impl the trait for it. There's nothing the wrapper needs to validate in this situation, it is merely useful for satisfying coherence.

2 Likes

You're right :slight_smile:

The problem is that there's no rule that guarantees an impl like impl<T> From<T> for MyType won't exist, and that impl would conflict with your implementation.

Ahh, I see. Is there a workaround for this?

Design wise, if your newtype doesn't enforce rules why do you need it?

It does enforce rules :slight_smile: Even if I can make one from any T I can expose only the interface I want. It's also useful for example as a poor man's named arguments.

1 Like

Macros. Instead of implementing impl<T> From<Foo<T>> for T you may implement dozen of such From implementations for types that you care about.

Nasty kludge but standard library are full of these and if there would have been better choice then something else would have been used instead: not only authors of std are [supposed to] know Rust better than anyone, but std may use superpowers of unstable Rust!

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.