-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
document PartialEq, PartialOrd, Ord requirements more explicitly #85637
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,12 +27,25 @@ use self::Ordering::*; | |
/// Trait for equality comparisons which are [partial equivalence | ||
/// relations](https://en.wikipedia.org/wiki/Partial_equivalence_relation). | ||
/// | ||
/// `x.eq(y)` can also be written `x == y`, and `x.ne(y)` can be written `x != y`. | ||
/// We use the easier-to-read infix notation in the remainder of this documentation. | ||
/// | ||
/// This trait allows for partial equality, for types that do not have a full | ||
/// equivalence relation. For example, in floating point numbers `NaN != NaN`, | ||
/// so floating point types implement `PartialEq` but not [`trait@Eq`]. | ||
/// | ||
/// Formally, the equality must be (for all `a`, `b`, `c` of type `A`, `B`, | ||
/// `C`): | ||
/// Implementations must ensure that `eq` and `ne` are consistent with each other: | ||
/// | ||
/// - `a != b` if and only if `!(a == b)` | ||
/// (ensured by the default implementation). | ||
/// | ||
/// If [`PartialOrd`] or [`Ord`] are also implemented for `Self` and `Rhs`, their methods must also | ||
/// be consistent with `PartialEq` (see the documentation of those traits for the exact | ||
/// requirememts). It's easy to accidentally make them disagree by deriving some of the traits and | ||
/// manually implementing others. | ||
/// | ||
/// The equality relation `==` must satisfy the following conditions | ||
/// (for all `a`, `b`, `c` of type `A`, `B`, `C`): | ||
/// | ||
/// - **Symmetric**: if `A: PartialEq<B>` and `B: PartialEq<A>`, then **`a == b` | ||
/// implies `b == a`**; and | ||
|
@@ -53,15 +66,6 @@ use self::Ordering::*; | |
/// | ||
/// ## How can I implement `PartialEq`? | ||
/// | ||
/// `PartialEq` only requires the [`eq`] method to be implemented; [`ne`] is defined | ||
/// in terms of it by default. Any manual implementation of [`ne`] *must* respect | ||
/// the rule that [`eq`] is a strict inverse of [`ne`]; that is, `!(a == b)` if and | ||
/// only if `a != b`. | ||
/// | ||
/// Implementations of `PartialEq`, [`PartialOrd`], and [`Ord`] *must* agree with | ||
/// each other. It's easy to accidentally make them disagree by deriving some | ||
/// of the traits and manually implementing others. | ||
/// | ||
/// An example implementation for a domain in which two books are considered | ||
/// the same book if their ISBN matches, even if the formats differ: | ||
/// | ||
|
@@ -631,10 +635,25 @@ impl<T: Clone> Clone for Reverse<T> { | |
|
||
/// Trait for types that form a [total order](https://en.wikipedia.org/wiki/Total_order). | ||
/// | ||
/// An order is a total order if it is (for all `a`, `b` and `c`): | ||
/// Implementations must be consistent with the [`PartialOrd`] implementation, and ensure | ||
/// `max`, `min`, and `clamp` are consistent with `cmp`: | ||
/// | ||
/// - `partial_cmp(a, b) == Some(cmp(a, b))`. | ||
/// - `max(a, b) == max_by(a, b, cmp)` (ensured by the default implementation). | ||
/// - `min(a, b) == min_by(a, b, cmp)` (ensured by the default implementation). | ||
/// - For `a.clamp(min, max)`, see the [method docs](#method.clamp) | ||
/// (ensured by the default implementation). | ||
/// | ||
/// It's easy to accidentally make `cmp` and `partial_cmp` disagree by | ||
/// deriving some of the traits and manually implementing others. | ||
/// | ||
/// ## Corollaries | ||
/// | ||
/// From the above and the requirements of `PartialOrd`, it follows that `<` defines a strict total order. | ||
/// This means that for all `a`, `b` and `c`: | ||
/// | ||
/// - total and asymmetric: exactly one of `a < b`, `a == b` or `a > b` is true; and | ||
/// - transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. | ||
/// - exactly one of `a < b`, `a == b` or `a > b` is true; and | ||
/// - `<` is transitive: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. | ||
/// | ||
/// ## Derivable | ||
/// | ||
|
@@ -659,12 +678,6 @@ impl<T: Clone> Clone for Reverse<T> { | |
/// Then you must define an implementation for [`cmp`]. You may find it useful to use | ||
/// [`cmp`] on your type's fields. | ||
/// | ||
/// Implementations of [`PartialEq`], [`PartialOrd`], and `Ord` *must* | ||
/// agree with each other. That is, `a.cmp(b) == Ordering::Equal` if | ||
/// and only if `a == b` and `Some(a.cmp(b)) == a.partial_cmp(b)` for | ||
/// all `a` and `b`. It's easy to accidentally make them disagree by | ||
/// deriving some of the traits and manually implementing others. | ||
/// | ||
/// Here's an example where you want to sort people by height only, disregarding `id` | ||
/// and `name`: | ||
/// | ||
|
@@ -824,15 +837,45 @@ impl PartialOrd for Ordering { | |
|
||
/// Trait for values that can be compared for a sort-order. | ||
/// | ||
/// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using | ||
/// the `<`, `<=`, `>`, and `>=` operators, respectively. | ||
/// | ||
/// The methods of this trait must be consistent with each other and with those of `PartialEq` in | ||
/// the following sense: | ||
/// | ||
/// - `a == b` if and only if `partial_cmp(a, b) == Some(Equal)`. | ||
/// - `a < b` if and only if `partial_cmp(a, b) == Some(Less)` | ||
/// (ensured by the default implementation). | ||
/// - `a > b` if and only if `partial_cmp(a, b) == Some(Greater)` | ||
/// (ensured by the default implementation). | ||
/// - `a <= b` if and only if `a < b || a == b` | ||
/// (ensured by the default implementation). | ||
/// - `a >= b` if and only if `a > b || a == b` | ||
/// (ensured by the default implementation). | ||
/// - `a != b` if and only if `!(a == b)` (already part of `PartialEq`). | ||
/// | ||
/// If [`Ord`] is also implemented for `Self` and `Rhs`, it must also be consistent with | ||
/// `partial_cmp` (see the documentation of that trait for the exact requirements). It's | ||
/// easy to accidentally make them disagree by deriving some of the traits and manually | ||
/// implementing others. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same thought as above on an example. |
||
/// | ||
/// The comparison must satisfy, for all `a`, `b` and `c`: | ||
/// | ||
/// - asymmetry: if `a < b` then `!(a > b)`, as well as `a > b` implying `!(a < b)`; and | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I removed this line because:
asymmtery (in the correct sense of the word) is a consequence of duality, so we could state it in the corollary section if you wish. antisymmetry is more closely related to what the docs are currently stating, but it is defined for |
||
/// - transitivity: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. | ||
/// - duality: `a < b` if and only if `b > a`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is probably the most questionable part of this PR -- it could be considered a new requirement. On the other hand, given that we demand symmetry for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is probably the most questionable part of this PR -- it could be considered a new requirement. On the other hand, given that we demand symmetry for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is another property here that we might want to add: compatibility of |
||
/// | ||
/// Note that these requirements mean that the trait itself must be implemented symmetrically and | ||
/// transitively: if `T: PartialOrd<U>` and `U: PartialOrd<V>` then `U: PartialOrd<T>` and `T: | ||
/// PartialOrd<V>`. | ||
/// | ||
/// ## Corollaries | ||
/// | ||
/// The following corollaries follow from the above requirements: | ||
/// | ||
/// - irreflexivity of `<` and `>`: `!(a < a)`, `!(a > a)` | ||
/// - transitivity of `>`: if `a > b` and `b > c` then `a > c` | ||
/// - duality of `partial_cmp`: `partial_cmp(a, b) == partial_cmp(b, a).map(Ordering::reverse)` | ||
/// | ||
/// ## Derivable | ||
/// | ||
/// This trait can be used with `#[derive]`. When `derive`d on structs, it will produce a | ||
|
@@ -850,10 +893,6 @@ impl PartialOrd for Ordering { | |
/// | ||
/// `PartialOrd` requires your type to be [`PartialEq`]. | ||
/// | ||
/// Implementations of [`PartialEq`], `PartialOrd`, and [`Ord`] *must* agree with each other. It's | ||
/// easy to accidentally make them disagree by deriving some of the traits and manually | ||
/// implementing others. | ||
/// | ||
/// If your type is [`Ord`], you can implement [`partial_cmp`] by using [`cmp`]: | ||
/// | ||
/// ``` | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this sentence is begging for a code example. I was saying to myself, "Oh wow, I should watch out for that, I'm hoping an example comes next" while reading it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that I did not write this sentence, I just moved it around. I don't know what the original author had in their mind when writing this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So what I am saying is, this issue is pre-existing, and I hope my PR doesn't have to fix it. :) It seems largely orthogonal to what this PR is about.