Why `Box<T>` does not implement `PartialEq<Box<U>>` where `T: PartialEq<U>`?

Currently, the PartialEq implementation is defined like this:

impl<T: ?Sized + PartialEq> PartialEq for Box<T> {
    fn eq(&self, other: &Box<T>) -> bool {
        PartialEq::eq(&**self, &**other)
    }
    fn ne(&self, other: &Box<T>) -> bool {
        PartialEq::ne(&**self, &**other)
    }
}

Why is it not implemented for PartialEq<U> like this?

impl<T: ?Sized, U: ?Sized> PartialEq<Box<U>> for Box<T>
where
    T: PartialEq<U>,
{
    default fn eq(&self, other: &Box<U>) -> bool {
        PartialEq::eq(&**self, &**other)
    }
    default fn ne(&self, other: &Box<U>) -> bool {
        PartialEq::ne(&**self, &**other)
    }
}

Same applies to PartialOrd


EDIT: I updated the code to use specialization to prevent a semver-breaking change.

For the non-generic case, autoderef should handle it, which may be why it is less likely to be noticed.

In the generic case, I agree that this generalization is correct, and is a non-semver-breaking change (well, except for the fact that Box is #[fundamental] which has some special rules I don’t quite understand) but probably could easily lead to inference problems.

1 Like

AIUI, this means Box<Foo> has the same locality as Foo for the purpose of coherence, so adding a new blanket impl on Box<U> is a breaking change.

For example, I could have impl PartialEq<Box<Bar>> for Box<Foo> already.

2 Likes

With specialization, this could be solved, right?

Yes, specialization would solve that semver problem.

I updated the first post to cover this case. Thank you!

As for why we don’t have that default impl: the stdlib is very careful not to do anything that requires specialization yet, as it’s not stabilized yet (and still isn’t fully designed, there’s some really scary corners left).

Once specialization is stable, it might make sense to add this impl to the stdlib.

1 Like

internals.rust-lang is missing the solved-button like in users.rust-lang :wink:

the stdlib is very careful not to do anything that requires specialization yet, as it’s not stabilized yet

That's not true of liballoc, which does use specialization, and is what contains the Box type.

I’m pretty sure that nothing’s stabily exposed that’s impossible without specialization. (If there is, I’m wrong and I admit it, but I’ve seen potential specialization-requiring impls blocked on stabilized specialization.)

Of course, it’s being used for optimization. But only in the sense that the general impl works for all cases, and a subset is explicitly specialized to a more efficient path.

3 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.