Allow downstream conversion trait impls on newtypes?

I have a newtype wrapper Foo<T> which I want downstream users to be able to implement From (and other conversion traits) for. The simple approach is not possible because of coherence rules:

pub struct Foo<T>(T);

// In another crate:

struct Bar;

impl From<Foo<Bar>> for i32 {
    fn from(_: Foo<Bar>) -> Self {
        unimplemented!()
    }
}

impl From<u32> for Foo<Bar> {
    fn from(_: u32) -> Self {
        unimplemented!()
    }
}

But both of these implementations get an impl doesn't use only types from inside the current crate error (though replacing Foo with Box works, so maybe there's a way to opt into that behaviour?). To get around the issue I tried making a helper trait FromFoo<T>:

pub trait FromFoo<T> {
    fn from_foo(_: Foo<T>) -> Self;
}

impl<T, U: FromFoo<T>> From<Foo<T>> for U {
    fn from(foo: Foo<T>) -> Self {
        Self::from_foo(foo)
    }
}

But this gives the following error:

  = note: conflicting implementation in crate `core`:
          - impl<T> From<T> for T;
  = note: downstream crates may implement trait `FromFoo<_>` for type `Foo<_>`

Is there a way to make the desired behaviour work (however restricted)? And if not, can you point me to issues on GitHub and/or RFCs that would allow this behaviour?

No. By design, the orphan rules will block you from doing this.

You'll need to drop the blanket impl From<Foo<T>> for U where U: FromFoo<T> if you want your FromFoo trait to work.

Yeah, I kinda figured, was just hoping there was some other workaround.

I'll probably do like you suggested, thanks for the help!

1 Like

The difference with Box is that it's marked #[fundamental]. This attribute is unstable, maybe permanently. Although there are some arguments for stabilizing it. See issue #29635

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.