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
ByPtr
types. - use wrapper types like
ByAddress
.