-
Notifications
You must be signed in to change notification settings - Fork 14k
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,bandc:
- transitivity:
a < bandb < cimpliesa < c. The same must hold for both==and>.- duality:
a < bif 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 compileSo 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