No... but nonetheless, a decision had to be made for the sake of generic code.
In my honest view, I do not always consider None
as the "absence" of a value. Sometimes I do; and other times, I consider it to be just another value (where Option
is used to extend a type with a single additional value).
This problem doesn't just affect Option. Many types that have normally have no business at all being compared are given PartialOrd
and Ord
implementations simply for the sake of supporting algorithms. A crate like num-complex
has to make a tough decision:
- if
Complex
does not deriveOrd
, you won't be able to do cool things like construct aBTreeMap
whose keys are gaussian integers. - If
Complex
does deriveOrd
, everybody's code will be full of heinous bugs where they accidentally used the<
operator on complex numbers.
All things considered, I wish Rust did not conflate the ordered comparisons we care about (i.e. the places where we actually want to use <
and max
) together with the ordered comparisons that exist because they can (i.e. the kind that are used by BTreeMap
and algorithms). I imagine an alternate universe with three traits:
// * can use #[derive(Lex)]
// * used in bounds for BTreeMap
// * there might also be a Vec::lex_sort
/// Trait for lexical comparisons.
trait Lex {
fn lex_cmp(&self, other: &Self) -> Ordering;
}
// * cannot be derived (it now serves a role like Add and Sub)
/// Trait for the `<`, `>`, and etc. operators.
trait PartialOrd {
fn partial_cmp(&self, other: &Self) -> Option<Ordering>;
}
// * cannot be derived
// * used by Vec::sort, Iterator::min, Iterator::max
trait Ord: PartialOrd + Eq {
fn cmp(&self, other: &Self) -> Ordering { ... }
fn min(&self, other: &Self) -> &Self { ... }
fn max(&self, other: &Self) -> &Self { ... }
}