Skip to content

Commit baaf6d7

Browse files
committed
explain what crates should do when adding comparison with foreign types
1 parent 3e389ef commit baaf6d7

File tree

1 file changed

+38
-0
lines changed

1 file changed

+38
-0
lines changed

library/core/src/cmp.rs

+38
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,25 @@ use self::Ordering::*;
7878
/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these
7979
/// methods.
8080
///
81+
/// ## Cross-crate considerations
82+
///
83+
/// Upholding the requirements stated above can become tricky when one crate implements `PartialEq`
84+
/// for a type of another crate (i.e., to allow comparing one of its own types with a type from the
85+
/// standard library). The recommendation is to never implement this trait for a foreign type. In
86+
/// other words, such a crate should do `impl PartialEq<ForeignType> for LocalType`, but it should
87+
/// *not* do `impl PartialEq<LocalType> for ForeignType`.
88+
///
89+
/// This avoids the problem of transitive chains that criss-cross crate boundaries: for all local
90+
/// types `T`, you may assue that no other crate will add `impl`s that allow comparing `T == U`. In
91+
/// other words, if other crates add `impl`s that allow building longer transitive chains `U1 == ...
92+
/// == T == V1 == ...`, then all the types that appear to the right of `T` must be types that the
93+
/// crate defining `T` already knows about. This rules out transitive chains where downstream crates
94+
/// can add new `impl`s that "stitch together" comparisons of foreign types in ways that violate
95+
/// transitivity.
96+
///
97+
/// Not having such foreign `impl`s also avoids forward compatibility issues where one crate adding
98+
/// more `PartialEq` implementations can cause build failures in downstream crates.
99+
///
81100
/// ## Derivable
82101
///
83102
/// This trait can be used with `#[derive]`. When `derive`d on structs, two
@@ -939,6 +958,25 @@ pub macro Ord($item:item) {
939958
/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these
940959
/// methods.
941960
///
961+
/// ## Cross-crate considerations
962+
///
963+
/// Upholding the requirements stated above can become tricky when one crate implements `PartialOrd`
964+
/// for a type of another crate (i.e., to allow comparing one of its own types with a type from the
965+
/// standard library). The recommendation is to never implement this trait for a foreign type. In
966+
/// other words, such a crate should do `impl PartialOrd<ForeignType> for LocalType`, but it should
967+
/// *not* do `impl PartialOrd<LocalType> for ForeignType`.
968+
///
969+
/// This avoids the problem of transitive chains that criss-cross crate boundaries: for all local
970+
/// types `T`, you may assue that no other crate will add `impl`s that allow comparing `T < U`. In
971+
/// other words, if other crates add `impl`s that allow building longer transitive chains `U1 < ...
972+
/// < T < V1 < ...`, then all the types that appear to the right of `T` must be types that the crate
973+
/// defining `T` already knows about. This rules out transitive chains where downstream crates can
974+
/// add new `impl`s that "stitch together" comparisons of foreign types in ways that violate
975+
/// transitivity.
976+
///
977+
/// Not having such foreign `impl`s also avoids forward compatibility issues where one crate adding
978+
/// more `PartialOrd` implementations can cause build failures in downstream crates.
979+
///
942980
/// ## Corollaries
943981
///
944982
/// The following corollaries follow from the above requirements:

0 commit comments

Comments
 (0)