Summary
Change the behavior of Rc<T>::{partial_cmp, cmp, eq, hash} by calling respective methods on &T, instead of T.
Motivation
Currently, I am implementing a library that allows users to mark a type ByPtr. It overrides the default implementations of PartialOrd<&T>, Ord, PartialEq<&T>, Eq and
Hash for &T (thanks to &T being fundamental)
to compare and hash the references by address (rather than the default by-inner-value behavior),
pretty much like objects in Java and Python.
(The rationale that I chose to override traits for &T, but not T, is that by-address impl of traits for T violates the contract of several commonly used collections, e.g. HashSet, which requires the hash value doesn't change as the object moves. Impl for &T doesn't have this issue.)
However, smart pointers to these types are incomparable, as the current implementation calls the
respective methods on their inner values. I think that it can be relaxed to calling the respective
methods on &T.
Note that the change is a true relaxation: old code that compiles still compiles with the identical
semantics. This is because by definition of &T: PartialOrd where T: PartialOrd (in core::cmp), T: PartialOrd implies &T: PartialOrd, and comparing &T is effectively comparing the inner value in such case.
(please correct me if I made any mistakes)
Proposed Change
The current implementations of PartialOrd for Rc<T: ?Sized + PartialOrd> is:
fn partial_cmp(&self, other: &Rc<T>) -> Option<Ordering> {
(**self).partial_cmp(&**other)
}
we may change it as:
impl<T: ?Sized> PartialOrd for Rc<T>
where for<'a> &'a T: PartialOrd<&'a T>
{
fn partial_cmp(&self, other: &Rc<T>) -> Option<Ordering> {
(&**self).partial_cmp(&&**other)
}
}
(thanks to HRTB)
and likewise for Ord, PartialEq, Eq and Hash, and those of Arc.
Alternative methods
- provide a separate version of smart pointers for
ByPtrtypes. - use wrapper types like
ByAddress.