Skip to content

Commit 1cfc187

Browse files
committed
document PartialEq, PartialOrd, Ord requirements more explicitly
1 parent bf24e6b commit 1cfc187

File tree

1 file changed

+53
-23
lines changed

1 file changed

+53
-23
lines changed

library/core/src/cmp.rs

+53-23
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,23 @@ use self::Ordering::*;
2727
/// Trait for equality comparisons which are [partial equivalence
2828
/// relations](https://en.wikipedia.org/wiki/Partial_equivalence_relation).
2929
///
30+
/// `x.eq(y)` can also be written `x == y`, and `x.ne(y)` can be written `x != y`.
31+
/// We use the easier-to-read infix notation in the remainder of this documentation.
32+
///
3033
/// This trait allows for partial equality, for types that do not have a full
3134
/// equivalence relation. For example, in floating point numbers `NaN != NaN`,
3235
/// so floating point types implement `PartialEq` but not [`trait@Eq`].
3336
///
34-
/// Formally, the equality must be (for all `a`, `b`, `c` of type `A`, `B`,
35-
/// `C`):
37+
/// Implementations must ensure that `eq` and `ne` are consistent with each other:
38+
/// `a != b` if and only if `!(a == b)`.
39+
/// This is ensured by the default implementation of `ne`.
40+
/// If [`PartialOrd`] or [`Ord`] are also implemented for `Self` and `Rhs`, their methods must also
41+
/// be consistent with `PartialEq` (see the documentation of those traits for the exact
42+
/// requirememts). It's easy to accidentally make them disagree by deriving some of the traits and
43+
/// manually implementing others.
44+
///
45+
/// The equality relation `==` must satisfy the following conditions
46+
/// (for all `a`, `b`, `c` of type `A`, `B`, `C`):
3647
///
3748
/// - **Symmetric**: if `A: PartialEq<B>` and `B: PartialEq<A>`, then **`a == b`
3849
/// implies `b == a`**; and
@@ -53,15 +64,6 @@ use self::Ordering::*;
5364
///
5465
/// ## How can I implement `PartialEq`?
5566
///
56-
/// `PartialEq` only requires the [`eq`] method to be implemented; [`ne`] is defined
57-
/// in terms of it by default. Any manual implementation of [`ne`] *must* respect
58-
/// the rule that [`eq`] is a strict inverse of [`ne`]; that is, `!(a == b)` if and
59-
/// only if `a != b`.
60-
///
61-
/// Implementations of `PartialEq`, [`PartialOrd`], and [`Ord`] *must* agree with
62-
/// each other. It's easy to accidentally make them disagree by deriving some
63-
/// of the traits and manually implementing others.
64-
///
6567
/// An example implementation for a domain in which two books are considered
6668
/// the same book if their ISBN matches, even if the formats differ:
6769
///
@@ -634,7 +636,19 @@ impl<T: Clone> Clone for Reverse<T> {
634636
/// An order is a total order if it is (for all `a`, `b` and `c`):
635637
///
636638
/// - total and asymmetric: exactly one of `a < b`, `a == b` or `a > b` is true; and
637-
/// - transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
639+
/// - transitive: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
640+
///
641+
/// Implementations of [`PartialEq`], [`PartialOrd`], and `Ord` *must* agree with each other (for
642+
/// all `a` and `b`):
643+
///
644+
/// - `a.partial_cmp(b) == Some(a.cmp(b))`
645+
/// - `a.cmp(b) == Ordering::Equal` if and only if `a == b`
646+
/// (already follows from the above and the requirements of `PartialOrd`)
647+
///
648+
/// It's easy to accidentally make them disagree by
649+
/// deriving some of the traits and manually implementing others.
650+
///
651+
/// Furthermore, the `max`, `min`, and `clamp` methods of this trait must be consistent with `cmp`.
638652
///
639653
/// ## Derivable
640654
///
@@ -659,12 +673,6 @@ impl<T: Clone> Clone for Reverse<T> {
659673
/// Then you must define an implementation for [`cmp`]. You may find it useful to use
660674
/// [`cmp`] on your type's fields.
661675
///
662-
/// Implementations of [`PartialEq`], [`PartialOrd`], and `Ord` *must*
663-
/// agree with each other. That is, `a.cmp(b) == Ordering::Equal` if
664-
/// and only if `a == b` and `Some(a.cmp(b)) == a.partial_cmp(b)` for
665-
/// all `a` and `b`. It's easy to accidentally make them disagree by
666-
/// deriving some of the traits and manually implementing others.
667-
///
668676
/// Here's an example where you want to sort people by height only, disregarding `id`
669677
/// and `name`:
670678
///
@@ -824,15 +832,41 @@ impl PartialOrd for Ordering {
824832

825833
/// Trait for values that can be compared for a sort-order.
826834
///
835+
/// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using
836+
/// the `<`, `<=`, `>`, and `>=` operators, respectively.
837+
///
838+
/// The methods of this trait must be consistent with each other and with those of `PartialEq` in
839+
/// the following sense:
840+
///
841+
/// - `a == b` if and only if `partial_cmp(a, b) == Some(Equal)`.
842+
/// - `a < b` if and only if `partial_cmp(a, b) == Some(Less)`.
843+
/// - `a > b` if and only if `partial_cmp(a, b) == Some(Greater)`.
844+
/// - `a <= b` if and only if `a < b || a == b`.
845+
/// - `a >= b` if and only if `a > b || a == b`.
846+
/// - `a != b` if and only if `!(a == b)` (already part of `PartialEq`).
847+
///
848+
/// If [`Ord`] is also implemented for `Self` and `Rhs`, it must also be consistent with
849+
/// `partial_cmp` (see the documentation of that trait for the exact requirements). It's
850+
/// easy to accidentally make them disagree by deriving some of the traits and manually
851+
/// implementing others.
852+
///
827853
/// The comparison must satisfy, for all `a`, `b` and `c`:
828854
///
829-
/// - asymmetry: if `a < b` then `!(a > b)`, as well as `a > b` implying `!(a < b)`; and
830855
/// - transitivity: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
856+
/// - duality: `a < b` if and only if `b > a`.
831857
///
832858
/// Note that these requirements mean that the trait itself must be implemented symmetrically and
833859
/// transitively: if `T: PartialOrd<U>` and `U: PartialOrd<V>` then `U: PartialOrd<T>` and `T:
834860
/// PartialOrd<V>`.
835861
///
862+
/// ## Corollaries
863+
///
864+
/// The following corollaries follow from the above requirements:
865+
///
866+
/// - irreflexivity of `<` and `>`: `!(a < a)`, `!(a > a)`
867+
/// - transitivity of `>`: if `a > b` and `b > c` then `a > c`
868+
/// - duality of `partial_cmp`: `partial_cmp(a, b) == partial_cmp(b, a).map(Ordering::reverse)`
869+
///
836870
/// ## Derivable
837871
///
838872
/// This trait can be used with `#[derive]`. When `derive`d on structs, it will produce a
@@ -850,10 +884,6 @@ impl PartialOrd for Ordering {
850884
///
851885
/// `PartialOrd` requires your type to be [`PartialEq`].
852886
///
853-
/// Implementations of [`PartialEq`], `PartialOrd`, and [`Ord`] *must* agree with each other. It's
854-
/// easy to accidentally make them disagree by deriving some of the traits and manually
855-
/// implementing others.
856-
///
857887
/// If your type is [`Ord`], you can implement [`partial_cmp`] by using [`cmp`]:
858888
///
859889
/// ```

0 commit comments

Comments
 (0)