about summary refs log tree commit diff
path: root/library/core
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2023-12-26 19:52:20 +0100
committerRalf Jung <post@ralfj.de>2023-12-26 20:02:39 +0100
commitbaaf6d706ac3cb8b306ebede165706b7a0038415 (patch)
treee2fad16ec3f6bc89a82fa6f41b9a125f15832e96 /library/core
parent3e389ef6d50c2cae6b561a04adb9224e666eb964 (diff)
downloadrust-baaf6d706ac3cb8b306ebede165706b7a0038415.tar.gz
rust-baaf6d706ac3cb8b306ebede165706b7a0038415.zip
explain what crates should do when adding comparison with foreign types
Diffstat (limited to 'library/core')
-rw-r--r--library/core/src/cmp.rs38
1 files changed, 38 insertions, 0 deletions
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index e95410ba648..9c18d5573e6 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -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: