Description
What it does
When a type manually implements both PartialOrd
and Ord
, both implementations must agree i.e. behave the same way. Usually, the function bodies of ord
and partial_ord
are identical, save for wrapping the return expression in Some()
for partial_ord
. This is unnecessarily repetitive and makes the code more prone to error during refactoring, as one may forget to update one of the implementations. The best way of implementing these traits manually is to implement PartialOrd
in terms of Ord
, which reduces code duplication and guarantees that they function in the same way.
This lint should not trigger if the bounds on the impl for Ord
are more restrictive than the bounds on PartialOrd
.
Real-world example: bevyengine/bevy#8529 (comment).
Lint Name
duplicate_manual_partial_ord_impl
Category
style, complexity
Advantage
- The code is less repetitive.
- Implementations of
PartialOrd
andOrd
are guaranteed to agree. This is safer for future refactoring, since you can't forget to update one of the two impls.
Drawbacks
Will trigger on code that isn't broken which may be annoying, but following the lint's advice will always (as far as I can tell) make the code more robust.
Example
impl Ord for F {
fn cmp(&self, other: &Self) -> Ordering {
match self.a.cmp(&other.b) {
// .. some complex logic
}
}
}
impl PartialOrd for F {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(match self.a.cmp(&other.b) {
// .. some complex logic
})
}
}
Could be written as:
impl Ord for F { /* Unchanged */ }
impl PartialOrd for F {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}