Conflicting implementations when deal with `Borrow`

I want to implement some trait on types which implemented Borrow:

struct Foo {}
struct Bar {}

trait Baz {}

impl <T: Borrow<Foo>> Baz for T {}
impl <T: Borrow<Bar>> Baz for T {}

But the compiler said the implementation is conflicted.
I didn't figure out where is the overlapped implementations, T: Borrow<Foo> are types like Arc<Foo>, Box<Foo>, and T: Borrow<Bar> are types like Arc<Bar>, Box<Bar>, they are different types.

So where is the overlapping happens?

P.S. Maybe this an X/Y problem, what I want is that the type

pub struct Wrapper<T: Baz> {
    baz: T
}

Can accept types like Foo, Arc<Foo>, Box<Foo> (any types which can be refered as Foo), as long as Foo implements Baz. So do the Bar type.

There's nothing stopping FooBar from having both Borrow<Foo> and Borrow<Bar>.

So in this case, how should I accomplish my goal? The trait Baz is private, and Foo and Bar are types I can control, and there is no situation like FooBar in my project, any idea?

There's no way, since the FooBar type might be in the consumer crate.

I update my question, maybe this is an X/Y problem.

It's tedious, but if Baz is only for local use, then you can implement it for each of the variants that you care about, rather than trying to have a blanket Baz for T. Macros can make this a little easier.

That's what I'm doing now, but I have a feeling that the Baz will finally be public someday :rofl: I'm seeking unstable features and found one called "associated_type_bounds", but it seems not solving my problem.

You can use Deref instead of Borrow, because Deref can't have conflicting implementations. This doesn't entirely help, because the compiler doesn't fully reason about that to see that they're exclusive, but you can then also say that the Derefs that qualify are not Derefs to either Foo or Bar but Derefs to something that implements Baz — and, given that we're using Deref, we do need a separate impl Baz for Foo since Foo itself doesn't deref to Foo.

That is, this will compile:

use std::ops::Deref;

struct Foo {}
struct Bar {}

trait Baz {}

impl Baz for Foo {}
impl Baz for Bar {}
impl<T> Baz for T
where
    T: Deref,
    T::Target: Baz,
{}

However, it's more usual to do this kind of forwarding impl explicitly for individual smart pointer types, not to write a blanket impl of this type. I don't recall this second whether there's a concrete reason to prefer that, though in general, having a blanket impl narrows what other impls can be written.

1 Like

Generally, how the standard library handles it is to have a separate impl for each container type. In this case, it would look something like this:

use std::{rc::Rc, sync::Arc};

struct Foo {}
struct Bar {}

trait Baz {}

impl Baz for Foo {}
impl Baz for Bar {}
impl<T: Baz + ?Sized> Baz for &T {}
impl<T: Baz + ?Sized> Baz for &mut T {}
impl<T: Baz + ?Sized> Baz for Box<T> {}
impl<T: Baz + ?Sized> Baz for Rc<T> {}
impl<T: Baz + ?Sized> Baz for Arc<T> {}
1 Like

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.