Skip to content

Commit 3bcad65

Browse files
committed
Auto merge of #103046 - JanBeh:PR_clarify_cmp_terminology, r=workingjubilee
docs: Correct terminology in std::cmp This PR is the result of some discussions on URLO: * [Traits in `std::cmp` and mathematical terminology](https://users.rust-lang.org/t/traits-in-std-cmp-and-mathematical-terminology/69887) * [Are poker hands `Ord` or `PartialOrd`?](https://users.rust-lang.org/t/are-poker-hands-ord-or-partialord/82644) Arguably, the documentation currently isn't very precise regarding mathematical terminology. This can lead to misunderstandings of what `PartialEq`, `Eq`, `PartialOrd`, and `Ord` actually do. While I believe this PR doesn't give any new API guarantees, it expliclitly mentions that `PartialEq::eq(a, b)` may return `true` for two distinct values `a` and `b` (i.e. where `a` and `b` are not equal in the mathematical sense). This leads to the consequence that `Ord` may describe a weak ordering instead of a total ordering. In either case, I believe this PR should be thoroughly reviewed, ideally by someone with mathematical background to make sure the terminology is correct now, and also to ensure that no unwanted new API guarantees are made. In particular, the following problems are addressed: * Some clarifications regarding used (mathematical) terminology: * Avoid using the terms "total equality" and "partial equality" in favor of "equivalence relation" and "partial equivalence relation", which are well-defined and unambiguous. * Clarify that `Ordering` is an ordering between two values (and not an order in the mathematical sense). * Avoid saying that `PartialEq` and `Eq` are "equality comparisons" because the terminology "equality comparison" could be misleading: it's possible to implement `PartialEq` and `Eq` for other (partial) equivalence relations, in particular for relations where `a == b` for some `a` and `b` even when `a` and `b` are not the same value. * Added a section "Strict and non-strict partial orders" to document that the `<=` and `>=` operators do not correspond to non-strict partial orders. * Corrected section "Corollaries" in documenation of `Ord` in regard to `<` only describing a strict total order in cases where `==` conforms to mathematical equality. * ~~Added a section "Weak orders" to explain that `Ord` may also describe a weak order or total preorder, depending on how `PartialEq::eq` has been implemented.~~ (Removed, see [comment](#103046 (comment))) * Made documentation easier to understand: * Explicitly state at the beginning of `PartialEq`'s documentation comment that implementing the trait will provide the `==` and `!=` operators. * Added an easier to understand rule when to implement `Eq` in addition to `PartialEq`: "if it’s guaranteed that `PartialEq::eq(a, a)` always returns `true`." * Explicitly mention in documentation of `Eq` that the properties "symmetric" and "transitive" are already required by `PartialEq`.
2 parents cf9fd95 + 86b031b commit 3bcad65

File tree

1 file changed

+50
-17
lines changed

1 file changed

+50
-17
lines changed

library/core/src/cmp.rs

+50-17
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@
33
//! This module contains various tools for comparing and ordering values. In
44
//! summary:
55
//!
6-
//! * [`Eq`] and [`PartialEq`] are traits that allow you to define total and
7-
//! partial equality between values, respectively. Implementing them overloads
8-
//! the `==` and `!=` operators.
6+
//! * [`PartialEq<Rhs>`] overloads the `==` and `!=` operators. In cases where
7+
//! `Rhs` (the right hand side's type) is `Self`, this trait corresponds to a
8+
//! partial equivalence relation.
9+
//! * [`Eq`] indicates that the overloaded `==` operator corresponds to an
10+
//! equivalence relation.
911
//! * [`Ord`] and [`PartialOrd`] are traits that allow you to define total and
1012
//! partial orderings between values, respectively. Implementing them overloads
1113
//! the `<`, `<=`, `>`, and `>=` operators.
1214
//! * [`Ordering`] is an enum returned by the main functions of [`Ord`] and
13-
//! [`PartialOrd`], and describes an ordering.
15+
//! [`PartialOrd`], and describes an ordering of two values (less, equal, or
16+
//! greater).
1417
//! * [`Reverse`] is a struct that allows you to easily reverse an ordering.
1518
//! * [`max`] and [`min`] are functions that build off of [`Ord`] and allow you
1619
//! to find the maximum or minimum of two values.
@@ -27,16 +30,21 @@ pub(crate) use bytewise::BytewiseEq;
2730

2831
use self::Ordering::*;
2932

30-
/// Trait for equality comparisons.
33+
/// Trait for comparisons using the equality operator.
34+
///
35+
/// Implementing this trait for types provides the `==` and `!=` operators for
36+
/// those types.
3137
///
3238
/// `x.eq(y)` can also be written `x == y`, and `x.ne(y)` can be written `x != y`.
3339
/// We use the easier-to-read infix notation in the remainder of this documentation.
3440
///
35-
/// This trait allows for partial equality, for types that do not have a full
36-
/// equivalence relation. For example, in floating point numbers `NaN != NaN`,
37-
/// so floating point types implement `PartialEq` but not [`trait@Eq`].
38-
/// Formally speaking, when `Rhs == Self`, this trait corresponds to a [partial equivalence
39-
/// relation](https://en.wikipedia.org/wiki/Partial_equivalence_relation).
41+
/// This trait allows for comparisons using the equality operator, for types
42+
/// that do not have a full equivalence relation. For example, in floating point
43+
/// numbers `NaN != NaN`, so floating point types implement `PartialEq` but not
44+
/// [`trait@Eq`]. Formally speaking, when `Rhs == Self`, this trait corresponds
45+
/// to a [partial equivalence relation].
46+
///
47+
/// [partial equivalence relation]: https://en.wikipedia.org/wiki/Partial_equivalence_relation
4048
///
4149
/// Implementations must ensure that `eq` and `ne` are consistent with each other:
4250
///
@@ -242,15 +250,15 @@ pub macro PartialEq($item:item) {
242250
/* compiler built-in */
243251
}
244252

245-
/// Trait for equality comparisons which are [equivalence relations](
253+
/// Trait for comparisons corresponding to [equivalence relations](
246254
/// https://en.wikipedia.org/wiki/Equivalence_relation).
247255
///
248-
/// This means, that in addition to `a == b` and `a != b` being strict inverses, the equality must
249-
/// be (for all `a`, `b` and `c`):
256+
/// This means, that in addition to `a == b` and `a != b` being strict inverses,
257+
/// the relation must be (for all `a`, `b` and `c`):
250258
///
251259
/// - reflexive: `a == a`;
252-
/// - symmetric: `a == b` implies `b == a`; and
253-
/// - transitive: `a == b` and `b == c` implies `a == c`.
260+
/// - symmetric: `a == b` implies `b == a` (required by `PartialEq` as well); and
261+
/// - transitive: `a == b` and `b == c` implies `a == c` (required by `PartialEq` as well).
254262
///
255263
/// This property cannot be checked by the compiler, and therefore `Eq` implies
256264
/// [`PartialEq`], and has no extra methods.
@@ -260,6 +268,10 @@ pub macro PartialEq($item:item) {
260268
/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these
261269
/// methods.
262270
///
271+
/// Implement `Eq` in addition to `PartialEq` if it's guaranteed that
272+
/// `PartialEq::eq(a, a)` always returns `true` (reflexivity), in addition to
273+
/// the symmetric and transitive properties already required by `PartialEq`.
274+
///
263275
/// ## Derivable
264276
///
265277
/// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has
@@ -676,12 +688,19 @@ impl<T: Clone> Clone for Reverse<T> {
676688
///
677689
/// ## Corollaries
678690
///
679-
/// From the above and the requirements of `PartialOrd`, it follows that `<` defines a strict total order.
680-
/// This means that for all `a`, `b` and `c`:
691+
/// From the above and the requirements of `PartialOrd`, it follows that for
692+
/// all `a`, `b` and `c`:
681693
///
682694
/// - exactly one of `a < b`, `a == b` or `a > b` is true; and
683695
/// - `<` is transitive: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
684696
///
697+
/// Mathematically speaking, the `<` operator defines a strict [weak order]. In
698+
/// cases where `==` conforms to mathematical equality, it also defines a
699+
/// strict [total order].
700+
///
701+
/// [weak order]: https://en.wikipedia.org/wiki/Weak_ordering
702+
/// [total order]: https://en.wikipedia.org/wiki/Total_order
703+
///
685704
/// ## Derivable
686705
///
687706
/// This trait can be used with `#[derive]`.
@@ -920,6 +939,20 @@ pub macro Ord($item:item) {
920939
/// - transitivity of `>`: if `a > b` and `b > c` then `a > c`
921940
/// - duality of `partial_cmp`: `partial_cmp(a, b) == partial_cmp(b, a).map(Ordering::reverse)`
922941
///
942+
/// ## Strict and non-strict partial orders
943+
///
944+
/// The `<` and `>` operators behave according to a *strict* partial order.
945+
/// However, `<=` and `>=` do **not** behave according to a *non-strict*
946+
/// partial order.
947+
/// That is because mathematically, a non-strict partial order would require
948+
/// reflexivity, i.e. `a <= a` would need to be true for every `a`. This isn't
949+
/// always the case for types that implement `PartialOrd`, for example:
950+
///
951+
/// ```
952+
/// let a = f64::sqrt(-1.0);
953+
/// assert_eq!(a <= a, false);
954+
/// ```
955+
///
923956
/// ## Derivable
924957
///
925958
/// This trait can be used with `#[derive]`.

0 commit comments

Comments
 (0)