PartialEq/Eq/PartialOrd/Ord design question


#1

Despite I am using Rust since months, I am not yet afraid of asking simple questions :slight_smile: I don’t understand the design of PartialEq/Eq/PartialOrd/Ord. Currently I am seeing an asymmetry.

Currently the four traits are:

trait PartialEq<Rhs = Self> where Rhs: ?Sized {
    fn eq(&self, other: &Rhs) -> bool;
    //...
}

trait Eq: PartialEq<Self> {}

trait PartialOrd<Rhs = Self>: PartialEq<Rhs> where Rhs: ?Sized {
    fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>;
    //...
}

trait Ord: Eq + PartialOrd<Self> {
    fn cmp(&self, other: &Self) -> Ordering;
}

Why aren’t they designed like this:

trait PartialEq<Rhs = Self> where Rhs: ?Sized {
    fn partial_eq(&self, other: &Rhs) -> Option<bool>;
    //...
}

trait Eq: PartialEq<Self> {
    eq(&self, other: &Rhs) -> bool;
}

trait PartialOrd<Rhs = Self>: PartialEq<Rhs> where Rhs: ?Sized {
    fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>;
    //...
}

trait Ord: Eq + PartialOrd<Self> {
    fn cmp(&self, other: &Self) -> Ordering;
}

Or like this?

trait PartialEq<Rhs = Self> where Rhs: ?Sized {
    eq(&self, other: &Rhs) -> bool;
    //...
}

trait Eq: PartialEq<Self> {}

trait PartialOrd<Rhs = Self>: PartialEq<Rhs> where Rhs: ?Sized {
    fn partial_cmp(&self, other: &Rhs) -> Ordering;
    //...
}

trait Ord: Eq + PartialOrd<Self> {}

And related to that, here I don’t understand what function “a < b” is actually calling:

fn test<T: PartialOrd>(a: T, b: T) -> bool {
    if a < b { true } else { false }
}
fn main() {
    use std::f64::NAN;
    println!("{}", test(NAN, NAN)); // Output: false
}

partial_cmp() should return an Option. If T is PartialOrd then I think performing “a < b” should be disallowed, and you should just call partial_cmp() and handle the Option<>. Unless Ord is defined like:

trait Ord: Eq + PartialOrd<Self> {}

Just like in the “==” case.

(Lot of Rust design is very symmetric and clean, so unless I am missing some things I guess the asymmetry/kludge I am perceiving here was introduced for strong practicality reasons).


#2

IMO the current design is good.

As I understand it, all comparison operators will just return false, if partial_cmp returns None.
This also includes == and thus partial_eq is not necessary.

A full set of (overloaded) comparison operators (like e.g. in C++) that return just a bool is equivalent to partial_cmp.
I.e. the following should hold: !(a < b || b < a) == partial_cmp(a,b).is_none()


#3

My original post may sound like a critique, but it’s really a design rationale question, to help me understand better :slight_smile:


#4

Sorry if I sounded overly defensive, that wasn’t my intention. I wasn’t involved in that design and it’s even possible that I got it wrong… :slight_smile: