Rust: Blanket implementation of Eq if Ord is implemented

Created on 16 May 2019  路  5Comments  路  Source: rust-lang/rust

Quote from Trait std::cmp::Ord's documentation:

Ord requires that the type also be PartialOrd and Eq (which requires PartialEq).
[鈥
Implementations of PartialEq, PartialOrd, and Ord must agree with each other. That is, a.cmp(b) == Ordering::Equal if and only if a == 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:

  • If something implements Ord, it's obvious that it is Eq, PartialOrd and PartialEq.
  • If something is PartialOrd, it's obvious that it is PartialEq.
  • If it's neither of those, one can always implement the largest amount that can be implemented.

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.

Most helpful comment

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.

All 5 comments

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!

Was this page helpful?
0 / 5 - 0 ratings