Skip to content

Commit 62414b4

Browse files
committed
Correct and expand docs for PartialOrd
1 parent ae3e8c6 commit 62414b4

File tree

1 file changed

+93
-69
lines changed

1 file changed

+93
-69
lines changed

library/core/src/cmp.rs

Lines changed: 93 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
//! partial equivalence relation.
99
//! * [`Eq`] indicates that the overloaded `==` operator corresponds to an
1010
//! equivalence relation.
11-
//! * [`Ord`] and [`PartialOrd`] are traits that allow you to define total and
12-
//! partial orderings between values, respectively. Implementing them overloads
13-
//! the `<`, `<=`, `>`, and `>=` operators.
11+
//! * [`PartialOrd<Rhs>`] overloads the `<`, `<=`, `>`, and `>=` operators. If
12+
//! `Rhs` is `Self`, then `<` and `>` correspond to strict partial orders.
13+
//! * [`Ord`] indicates that exactly one of `x < y`, `x == y`, or `x > y` is
14+
//! true.
1415
//! * [`Ordering`] is an enum returned by the main functions of [`Ord`] and
1516
//! [`PartialOrd`], and describes an ordering of two values (less, equal, or
1617
//! greater).
@@ -1095,45 +1096,44 @@ pub macro Ord($item:item) {
10951096
/* compiler built-in */
10961097
}
10971098

1098-
/// Trait for types that form a [partial order](https://en.wikipedia.org/wiki/Partial_order).
1099+
/// Trait for overloading the `<`, `<=`, `>`, and `>=` operators.
10991100
///
1100-
/// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using the `<`, `<=`, `>`, and
1101-
/// `>=` operators, respectively.
1101+
/// The above operators call the the `lt`, `le`, `gt`, and `ge` methods of this trait, respectively.
11021102
///
11031103
/// This trait should **only** contain the comparison logic for a type **if one plans on only
11041104
/// implementing `PartialOrd` but not [`Ord`]**. Otherwise the comparison logic should be in [`Ord`]
11051105
/// and this trait implemented with `Some(self.cmp(other))`.
11061106
///
11071107
/// The methods of this trait must be consistent with each other and with those of [`PartialEq`].
1108-
/// The following conditions must hold:
1109-
///
1110-
/// 1. `a == b` if and only if `partial_cmp(a, b) == Some(Equal)`.
1111-
/// 2. `a < b` if and only if `partial_cmp(a, b) == Some(Less)`
1112-
/// 3. `a > b` if and only if `partial_cmp(a, b) == Some(Greater)`
1113-
/// 4. `a <= b` if and only if `a < b || a == b`
1114-
/// 5. `a >= b` if and only if `a > b || a == b`
1115-
/// 6. `a != b` if and only if `!(a == b)`.
1116-
///
1117-
/// Conditions 2–5 above are ensured by the default implementation. Condition 6 is already ensured
1118-
/// by [`PartialEq`].
1119-
///
1120-
/// If [`Ord`] is also implemented for `Self` and `Rhs`, it must also be consistent with
1108+
/// Specifically, in addition to the conditions of [`PartialEq`], the following **must** hold for
1109+
/// all values `a`, `b`, `c` of types `A: PartialOrd<B>`, `B`, `C` respectively:
1110+
///
1111+
/// 1. **Consistency:**
1112+
/// 1. `a == b` if and only if `partial_cmp(a, b) == Some(Equal)`.
1113+
/// 2. `a < b` if and only if `partial_cmp(a, b) == Some(Less)`
1114+
/// 3. `a > b` if and only if `partial_cmp(a, b) == Some(Greater)`
1115+
/// 4. `a <= b` if and only if `a < b || a == b` 5. `a >= b` if and only if `a > b || a == b`
1116+
/// 2. **Transitivity of `<`:** if `B: PartialOrd<C>` and `A: PartialOrd<C>`, then `a < b` and `b <
1117+
/// c` together imply `a < c`. This must also hold for longer chains, so that e.g. `a < b`, `b <
1118+
/// c`, and `c < d` together imply `a < d` whenever `d` is of type `D` such that `C:
1119+
/// PartialOrd<D>` and `A: PartialOrd<D>`.
1120+
/// 3. **Duality:** if `B: PartialOrd<A>`, then `a < b` if and only if `b > a`.
1121+
///
1122+
/// Conditions 1.2–1.5 above are ensured by the default implementation.
1123+
///
1124+
/// For 2 and 3, note that the `B: PartialOrd<A>` (dual) and `A: PartialOrd<C>` (transitive) impls
1125+
/// are not forced to exist, but these requirements apply whenever they do exist.
1126+
///
1127+
/// Also note that these requirements *do not* guarantee that `<=` and `>=` correspond to [partial
1128+
/// orders](https://en.wikipedia.org/wiki/Partial_order). However, they do guarantee that `<` and
1129+
/// `>` correspond to [strict partial orders](https://en.wikipedia.org/wiki/Strict_partial_order).
1130+
/// See the section [Strict and non-strict partial orders](PartialOrd#strict-and-non-strict-partial-orders)
1131+
/// below for more details.
1132+
///
1133+
/// If [`Ord`] is also implemented for `Self` and `Rhs`, it **must** also be consistent with
11211134
/// `partial_cmp` (see the documentation of that trait for the exact requirements). It's easy to
11221135
/// accidentally make them disagree by deriving some of the traits and manually implementing others.
11231136
///
1124-
/// The comparison relations must satisfy the following conditions (for all `a`, `b`, `c` of type
1125-
/// `A`, `B`, `C`):
1126-
///
1127-
/// - **Transitivity**: if `A: PartialOrd<B>` and `B: PartialOrd<C>` and `A: PartialOrd<C>`, then `a
1128-
/// < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. This must also
1129-
/// work for longer chains, such as when `A: PartialOrd<B>`, `B: PartialOrd<C>`, `C:
1130-
/// PartialOrd<D>`, and `A: PartialOrd<D>` all exist.
1131-
/// - **Duality**: if `A: PartialOrd<B>` and `B: PartialOrd<A>`, then `a < b` if and only if `b >
1132-
/// a`.
1133-
///
1134-
/// Note that the `B: PartialOrd<A>` (dual) and `A: PartialOrd<C>` (transitive) impls are not forced
1135-
/// to exist, but these requirements apply whenever they do exist.
1136-
///
11371137
/// Violating these requirements is a logic error. The behavior resulting from a logic error is not
11381138
/// specified, but users of the trait must ensure that such logic errors do *not* result in
11391139
/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these
@@ -1158,29 +1158,9 @@ pub macro Ord($item:item) {
11581158
/// Not having such foreign `impl`s also avoids forward compatibility issues where one crate adding
11591159
/// more `PartialOrd` implementations can cause build failures in downstream crates.
11601160
///
1161-
/// ## Corollaries
1162-
///
1163-
/// The following corollaries follow from the above requirements:
1164-
///
1165-
/// - irreflexivity of `<` and `>`: `!(a < a)`, `!(a > a)`
1166-
/// - transitivity of `>`: if `a > b` and `b > c` then `a > c`
1167-
/// - duality of `partial_cmp`: `partial_cmp(a, b) == partial_cmp(b, a).map(Ordering::reverse)`
1168-
///
1169-
/// ## Strict and non-strict partial orders
1170-
///
1171-
/// The `<` and `>` operators behave according to a *strict* partial order. However, `<=` and `>=`
1172-
/// do **not** behave according to a *non-strict* partial order. That is because mathematically, a
1173-
/// non-strict partial order would require reflexivity, i.e. `a <= a` would need to be true for
1174-
/// every `a`. This isn't always the case for types that implement `PartialOrd`, for example:
1175-
///
1176-
/// ```
1177-
/// let a = f64::sqrt(-1.0);
1178-
/// assert_eq!(a <= a, false);
1179-
/// ```
1180-
///
11811161
/// ## Derivable
11821162
///
1183-
/// This trait can be used with `#[derive]`.
1163+
/// This trait can be automatically implemented using `#[derive]`.
11841164
///
11851165
/// When `derive`d on structs, it will produce a
11861166
/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering based on the
@@ -1212,18 +1192,14 @@ pub macro Ord($item:item) {
12121192
/// assert!(E::Bottom < E::Top);
12131193
/// ```
12141194
///
1215-
/// ## How can I implement `PartialOrd`?
1195+
/// ## How can I manually implement `PartialOrd`?
12161196
///
12171197
/// `PartialOrd` only requires implementation of the [`partial_cmp`] method, with the others
12181198
/// generated from default implementations.
12191199
///
1220-
/// However it remains possible to implement the others separately for types which do not have a
1221-
/// total order. For example, for floating point numbers, `NaN < 0 == false` and `NaN >= 0 == false`
1222-
/// (cf. IEEE 754-2008 section 5.11).
1200+
/// ### Example: implementing `PartialOrd` using `Ord`
12231201
///
1224-
/// `PartialOrd` requires your type to be [`PartialEq`].
1225-
///
1226-
/// If your type is [`Ord`], you can implement [`partial_cmp`] by using [`cmp`]:
1202+
/// If your type is [`Ord`], you should implement [`partial_cmp`] by using [`cmp`]:
12271203
///
12281204
/// ```
12291205
/// use std::cmp::Ordering;
@@ -1255,9 +1231,11 @@ pub macro Ord($item:item) {
12551231
/// impl Eq for Person {}
12561232
/// ```
12571233
///
1258-
/// You may also find it useful to use [`partial_cmp`] on your type's fields. Here is an example of
1259-
/// `Person` types who have a floating-point `height` field that is the only field to be used for
1260-
/// sorting:
1234+
/// ### Example: implementing `PartialOrd` on a non-`Ord` type
1235+
///
1236+
/// Some types are `PartialOrd` but not [`Ord`]. For example, both `f64::NAN <= 0.0` and
1237+
/// `0.0 <= f64::NAN` are false, so [`f64`] cannot be `Ord`. Here is an example of a `Person` type
1238+
/// ordered by a floating-point `height`:
12611239
///
12621240
/// ```
12631241
/// use std::cmp::Ordering;
@@ -1281,7 +1259,7 @@ pub macro Ord($item:item) {
12811259
/// }
12821260
/// ```
12831261
///
1284-
/// ## Examples of incorrect `PartialOrd` implementations
1262+
/// ### Examples of incorrect `PartialOrd` implementations
12851263
///
12861264
/// ```
12871265
/// use std::cmp::Ordering;
@@ -1313,15 +1291,61 @@ pub macro Ord($item:item) {
13131291
/// assert_ne!(a, b); // a != b according to `PartialEq`.
13141292
/// ```
13151293
///
1316-
/// # Examples
1294+
/// ## Useful properties
1295+
///
1296+
/// The following corollaries follow from the above requirements for all values `a`, `b`, `c` of
1297+
/// type `A`, `B`, `C`:
1298+
///
1299+
/// 1. `<` and `>` are [irreflexive](https://en.wikipedia.org/wiki/Irreflexive_relation). That is, if `A: PartialOrd<A>`, then:
1300+
/// * `!(a < a)`.
1301+
/// * `!(a > a)`.
1302+
/// 2. `>`, `<=` and `>=` are also [transitive](https://en.wikipedia.org/wiki/Transitive_relation). That is, if `A: PartialOrd<B> + PartialOrd<C>` and `B:
1303+
/// PartialOrd<C>`, then:
1304+
/// * If `a > b` and `b > c`, then `a > c`.
1305+
/// * If `a <= b` and `b <= c`, then `a <= c`.
1306+
/// * If `a >= b` and `b >= c`, then `a >= c`.
1307+
/// 3. `<` and `>` are [asymmetric](https://en.wikipedia.org/wiki/Asymmetric_relation). That is, if `A: PartialOrd<B>` and `B: PartialOrd<A>`, then:
1308+
/// * If `a < b`, then `!(b < a)`;
1309+
/// * If `a > b`, then `!(b > a)`.
1310+
/// 4. `<=` and `>=` are [antisymmetric](https://en.wikipedia.org/wiki/Antisymmetric_relation) *modulo `==`*. That is, if `A: PartialOrd<B>` and `B: PartialOrd<A>`, then:
1311+
/// * If `a <= b` and `b <= a`, then `a == b`.
1312+
/// * If `a >= b` and `b >= a`, then `a == b`.
1313+
/// * The converses of the above also hold: `a == b` implies `a <= b`, `b <= a`, `a >= b`, and `b >= a`.
1314+
/// * Note that this is not antisymmetry in the usual sense, because `==` might not be the identity relation. (See below for further discussion.)
1315+
/// 5. Duality of `partial_cmp`: if `A: PartialOrd<B>` and `B: PartialOrd<A>`, then
1316+
/// `partial_cmp(a, b) == partial_cmp(b, a).map(Ordering::reverse)`
1317+
///
1318+
/// ## Strict and non-strict partial orders
1319+
///
1320+
/// For a type `T: PartialOrd`, the `<=` and `>=` relations are [partial orders](https://en.wikipedia.org/wiki/Partial_order)
1321+
/// on the type's values *if and only if* `==` is the identity relation. (This can be shown from
1322+
/// corollary 4.) However, this is not the case in general. For example, two distinct values can
1323+
/// compare equal under `==`:
13171324
///
13181325
/// ```
1319-
/// let x: u32 = 0;
1320-
/// let y: u32 = 1;
1326+
/// let a = -0.0;
1327+
/// let b = +0.0;
1328+
/// assert_ne!(a.to_bits(), b.to_bits()); // `a` and `b` are distinct because their sign bits differ.
1329+
/// assert!(a == b); // Yet they are equal under `==`.
1330+
/// assert!(a <= b && b <= a); // And so this is true (corollary 4).
1331+
/// ```
1332+
///
1333+
/// And `==` may return `false`, even when comparing a value against itself:
13211334
///
1322-
/// assert_eq!(x < y, true);
1323-
/// assert_eq!(x.lt(&y), true);
13241335
/// ```
1336+
/// let a = f64::sqrt(-1.0); // This produces a NaN.
1337+
/// assert_eq!(a == a, false); // Which does not compare equal to any value.
1338+
/// assert_eq!(a <= a, false); // Nor does it compare less than or equal to any value.
1339+
/// ```
1340+
///
1341+
/// However, corollaries 1-3 imply that `<` and `>` satisfy the definition of a
1342+
/// [*strict* partial order](https://en.wikipedia.org/wiki/Strict_partial_order).
1343+
///
1344+
/// More importantly, however, if `T` also implements [`Eq`], then `==` is an equivalence relation,
1345+
/// and from corollary 4 `<=` and `>=` give partial orders on its
1346+
/// [*equivalence classes*](https://en.wikipedia.org/wiki/Equivalence_class). This usually
1347+
/// suffices for when a partial order is required: we typically only care whether two objects "look"
1348+
/// the same, not whether they are exactly identical.
13251349
///
13261350
/// [`partial_cmp`]: PartialOrd::partial_cmp
13271351
/// [`cmp`]: Ord::cmp

0 commit comments

Comments
 (0)