Description
Std implementations of PartialOrd are violating the conditions regarding transitivity and symmetry.
From the standard library docs:
The comparison must satisfy, for all
a
,b
andc
:
- transitivity:
a < b
andb < c
impliesa < c
. The same must hold for both==
and>
.- duality:
a < b
if and only ifb > a
.Note that these requirements mean that the trait itself must be implemented symmetrically and transitively: if
T: PartialOrd<U>
andU: PartialOrd<V>
thenU: PartialOrd<T>
andT: PartialOrd<V>
.
(emphasis mine)
focus on the final paragraph in the quote above and look at the following example
use std::path::Path;
use std::ffi::OsStr;
let c: &str = "c";
let b: &OsStr = "b".as_ref();
let a: &Path = "a".as_ref();
assert!(b < c); // works
// assert!(c > b); // doesn’t compile
assert!(a < b && b < c); // works
// assert!(a < c); // doesn’t compile
So either the library documentation is off or the implementations are flawed.
And the transitivity requirements are impossible hard to ensure in a multi-crate ecosystem anyways.
Note that, technically, it’s impossible to enforce transitive existence of impls for the trait unless using operands of fully “external” types is completely prohibited:
If I’m writing a crate foo
providing a type struct Foo(…);
and an impl PartialOrd<i32> for Foo
as well as an impl PartialOrd<Foo> for i32
, it seems like I’m following the rules set by PartialOrd
’s documentation.
If I’m writing a crate bar
providing a type struct Bar(…);
and an impl PartialOrd<i32> for Bar
as well as an impl PartialOrd<Bar> for i32
, it seems like I’m following the rules set by PartialOrd
’s documentation.
Now, if I’m writing a third crate that imports both foo
and bar
, then I’ll have impl PartialOrd<Foo> for i32
as well as impl PartialOrd<i32> for Bar
, but obviously impl PartialOrd<Foo> for Bar
is missing.
In this example, the crates foo
and bar
each provided an impl
where one of the operands, i32
, was a type that’s fully external to the crate itself (in the sense that neither the type nor any of its generic arguments are part of foo
, or part of a different crate that has the same owners as foo
[i32
has no generic arguments to begin with]).
@rustbot label C-bug, T-libs