Skip to content

Commit

Permalink
explain what crates should do when adding comparison with foreign types
Browse files Browse the repository at this point in the history
RalfJung committed Dec 26, 2023
1 parent 3e389ef commit baaf6d7
Showing 1 changed file with 38 additions and 0 deletions.
38 changes: 38 additions & 0 deletions library/core/src/cmp.rs
Original file line number Diff line number Diff line change
@@ -78,6 +78,25 @@ use self::Ordering::*;
/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these
/// methods.
///
/// ## Cross-crate considerations
///
/// Upholding the requirements stated above can become tricky when one crate implements `PartialEq`
/// for a type of another crate (i.e., to allow comparing one of its own types with a type from the
/// standard library). The recommendation is to never implement this trait for a foreign type. In
/// other words, such a crate should do `impl PartialEq<ForeignType> for LocalType`, but it should
/// *not* do `impl PartialEq<LocalType> for ForeignType`.
///
/// This avoids the problem of transitive chains that criss-cross crate boundaries: for all local
/// types `T`, you may assue that no other crate will add `impl`s that allow comparing `T == U`. In
/// other words, if other crates add `impl`s that allow building longer transitive chains `U1 == ...
/// == T == V1 == ...`, then all the types that appear to the right of `T` must be types that the
/// crate defining `T` already knows about. This rules out transitive chains where downstream crates
/// can add new `impl`s that "stitch together" comparisons of foreign types in ways that violate
/// transitivity.
///
/// Not having such foreign `impl`s also avoids forward compatibility issues where one crate adding
/// more `PartialEq` implementations can cause build failures in downstream crates.
///
/// ## Derivable
///
/// This trait can be used with `#[derive]`. When `derive`d on structs, two
@@ -939,6 +958,25 @@ pub macro Ord($item:item) {
/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these
/// methods.
///
/// ## Cross-crate considerations
///
/// Upholding the requirements stated above can become tricky when one crate implements `PartialOrd`
/// for a type of another crate (i.e., to allow comparing one of its own types with a type from the
/// standard library). The recommendation is to never implement this trait for a foreign type. In
/// other words, such a crate should do `impl PartialOrd<ForeignType> for LocalType`, but it should
/// *not* do `impl PartialOrd<LocalType> for ForeignType`.
///
/// This avoids the problem of transitive chains that criss-cross crate boundaries: for all local
/// types `T`, you may assue that no other crate will add `impl`s that allow comparing `T < U`. In
/// other words, if other crates add `impl`s that allow building longer transitive chains `U1 < ...
/// < T < V1 < ...`, then all the types that appear to the right of `T` must be types that the crate
/// defining `T` already knows about. This rules out transitive chains where downstream crates can
/// add new `impl`s that "stitch together" comparisons of foreign types in ways that violate
/// transitivity.
///
/// Not having such foreign `impl`s also avoids forward compatibility issues where one crate adding
/// more `PartialOrd` implementations can cause build failures in downstream crates.
///
/// ## Corollaries
///
/// The following corollaries follow from the above requirements:

0 comments on commit baaf6d7

Please sign in to comment.