rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.88k stars 12.67k forks source link

Document "latent requirements" of PartialOrd #50230

Closed gnzlbg closed 3 years ago

gnzlbg commented 6 years ago

The PartialOrd docs do not document what is de facto required of trait implementors in order for data structures to work correctly. We should update them!

Per @RalfJung's comment below:

FWIW our conclusion was that we basically already require < to be irreflexive, since that is the only way the following equivalences can be upheld:

  • x < y iff x.partial_cmp(y) == Some(Less)
  • x == y iff x.partial_cmp(y) == Some(Equal)
  • x > y iff x.partial_cmp(y) == Some(Greater)

The docs are not explicitly stating that these equivalences must hold, but it seems very much against the spirit of this trait to allow violations of these equivalences. The fact that PartialOrd: PartialEq is very useful here as it makes the 2nd axiom well-defined.

This post used to say something different. Here is the original post Why doesn't `PartialOrd` require irreflexivity `!(a < a)` over `<` ? AFAICT `PartialOrd` does not actually express any kind of ordering relation for `<`. For: * a strict partial order on `<`: we need `PartialOrd` + `Irreflexivity` * non-strict partial order on `<=`: we need `PartialOrd` + `Eq` since `==` must be reflexive. * total order: we need`PartialOrd + Eq + Total` Is this an oversight? If not, we should document that `PartialOrd` requires: * irreflexivity: `!(a < a)` as well. That would make `PartialOrd`'s `<` denote a strict partial order on `<`. AFAICT this is actually what was intended, since all the discussions I can find online about `PartialOrd` talk about floats, and floats are strictly partially ordered under `<`, but not non-strictly partially ordered under `<=`, which would fit our current model that floats don't implement `Eq`. --- Also, the docs of `PartialOrd` do not say what `le` (`<=`) and `ge` (`>=`) actually mean. AFAICT they mean nothing for `PartialOrd` in isolation. From reading the source the default implementation is `a < b || a == b`, which would denote a non-strict total ordering over `<=` when `Eq` is implemented. But since `Eq` is not required for `PartialOrd`, I'd guess that those overriding these implementations are allowed to do something else as long as they don't implement `Eq`. It is unclear to me what that "something else" might mean, but the docs should probably say something about this. --- Also, I haven't been able to find any document explaining why things are the way they are, but the fact that `PartialOrd` requires `PartialEq` makes no sense to me, and it doesn't make much sense either that `PartialOrd` exposes `le` (`<=`) and `ge` (`>=`) methods, since as mentioned above, without `Eq`, `le` and `ge` do not express any meaningful ordering relation. It seems that these traits, like all other "operators" traits, mix operator overloading with mathematical semantics: in some cases they are used to express mathematical concepts, like a strict partial ordering relation under `<`, and in some other cases they are used "to provide <= for floats". If anybody has any links to any discussions / documentation about why things are the way they are I'd like to read them, and maybe we should add rationale sections to the docs.