Quote from Trait std::cmp::Ord's documentation:
Ordrequires that the type also bePartialOrdandEq(which requiresPartialEq).
[鈥
Implementations ofPartialEq,PartialOrd, andOrdmust agree with each other. That is,a.cmp(b) == Ordering::Equalif and only ifa == b[鈥 It's easy to accidentally make them disagree.
So, if it's easy to make them disagree, why not make Eq automatically implemented when someone defines Ord? It would be as simple as ordering == Eq.
In addition, the documentation doesn't explain why something must implement Eq for it to be Ord, which could be helpful for people to understand it.
This is how I think it should work:
Ord, it's obvious that it is Eq, PartialOrd and PartialEq.PartialOrd, it's obvious that it is PartialEq.A friend just shared Why does Eq require PartialEq? (Reddit) which further links to https://github.com/rust-lang/rfcs/pull/1028#issuecomment-91566317 explaining why such thing is not desirable, as well as another related issue https://github.com/rust-lang/rfcs/issues/441.
why not make Eq automatically implemented when someone defines Ord?
It's often a silent performance footgun.
For example, == for Vec can take a quick len()-based shortcut and fall back to element-wise comparison if the lengths are equal.
< always has to compare elements.
So, even if Eq for Vec is implemented correctly, the automatic Ord-based Eq implementation would still pessimize comparisons derived through Ord for all structures containing Vec.
It is understandable that == can often be faster than < but Ord does have a potential outcome Ordering::Equal for a reason (I presume sorting?) in which case implementing such a shortcut in the Ord implementation might also be worthwhile.
Furthermore, making a PartialEq implementation mandatory for Ord does go strongly against the DRY principle, while it can always be overridden in cases where a custom eq()implementation will give a significant speed boost, which I think the compiler is already capable of to some level because of the distinction between Less and Greater not mattering anymore. (I assume it is capable of reducing a code path that can only lead to false to just a return false; if there are no side effects)
Finally, the 'must agree' requirement is easier to adhere to with an automatic implementation, while it is probably easier to sneak in a subtle error when requiring them to be implemented seperately. As such making correct software is harder with this requirement.
That blanket implementation couldn't be added until specialization stabilizes.
A three-way comparison operator (<=>, "spaceship") is being added to C++20. It was originally proposed that the compiler auto-implement all six comparison operators in terms of (possibly defaulted) operator<=>, but they are now reconsidering the semantics exactly due to potential performance footguns especially in case of wrapper types.
Since this is both likely not actually desirable due to performance and not implementable until (if) specialization lands, I'm going to close this issue. Thanks!
Most helpful comment
It's often a silent performance footgun.
For example,
==forVeccan take a quicklen()-based shortcut and fall back to element-wise comparison if the lengths are equal.<always has to compare elements.So, even if
EqforVecis implemented correctly, the automaticOrd-basedEqimplementation would still pessimize comparisons derived throughOrdfor all structures containingVec.