Skip to content

Commit 18f92ff

Browse files
committed
RFC: Add a partial_cmp method to PartialOrd
1 parent 69a0f68 commit 18f92ff

File tree

1 file changed

+138
-0
lines changed

1 file changed

+138
-0
lines changed

active/0000-partial-cmp.md

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
- Start Date: 2014-06-01
2+
- RFC PR #: (leave this empty)
3+
- Rust Issue #: (leave this empty)
4+
5+
# Summary
6+
7+
Add a `partial_cmp` method to `PartialOrd`, analagous to `cmp` in `Ord`.
8+
9+
# Motivation
10+
11+
The `Ord::cmp` method is useful when working with ordered values. When the
12+
exact ordering relationship between two values is required, `cmp` is both
13+
potentially more efficient than computing both `a > b` and then `a < b` and
14+
makes the code clearer as well.
15+
16+
I feel that in the case of partial orderings, an equivalent to `cmp` is even
17+
more important. I've found that it's very easy to accidentally make assumptions
18+
that only hold true in the total order case (for example `!(a < b) => a >= b`).
19+
Explicitly matching against the possible results of the comparison helps keep
20+
these assumptions from creeping in.
21+
22+
In addition, the current default implementation setup is a bit strange, as
23+
implementations in the *partial* equality trait assume *total* equality. This
24+
currently makes it easier to incorrectly implement `PartialOrd` for types that
25+
do not have a total ordering, and if `PartialOrd` is separated from `Ord` in a
26+
way similar to [this](https://gist.github.com/alexcrichton/10945968) proposal,
27+
the default implementations for `PartialOrd` will need to be removed and an
28+
implementation of the trait will require four repetitive implementations of
29+
the required methods.
30+
31+
# Detailed design
32+
33+
Add an enum to `core::cmp`:
34+
```rust
35+
pub enum PartialOrdering {
36+
PartialOrdLess,
37+
PartialOrdEqual,
38+
PartialOrdGreater,
39+
PartialOrdUnordered,
40+
}
41+
```
42+
and a method to `PartialOrd`, changing the default implementations of the other
43+
methods:
44+
```rust
45+
pub trait PartialOrd {
46+
fn partial_cmp(&self, other: &Self) -> PartialOrdering;
47+
48+
fn lt(&self, other: &Self) -> bool {
49+
match self.partial_cmp(other) {
50+
PartialOrdLess => true,
51+
_ => false,
52+
}
53+
}
54+
55+
le(&self, other: &Self) -> bool {
56+
match self.partial_cmp(other) {
57+
PartialOrdLess | PartialOrdEqual => true,
58+
_ => false,
59+
}
60+
}
61+
62+
fn gt(&self, other: &Self) -> bool {
63+
match self.partial_cmp(other) {
64+
PartialOrdGreater => true,
65+
_ => false,
66+
}
67+
}
68+
69+
ge(&self, other: &Self) -> bool {
70+
match self.partial_cmp(other) {
71+
PartialOrdGreater | PartialOrdEqual => true,
72+
_ => false,
73+
}
74+
}
75+
}
76+
```
77+
78+
Since almost all ordered types have a total ordering, add a method to convert
79+
an `Ordering` to a `PartialOrdering`:
80+
```rust
81+
impl Ordering {
82+
pub fn to_partial(&self) -> PartialOrdering {
83+
Less => PartialOrdLess,
84+
Equal => PartialOrdEqual,
85+
Greater => PartialOrdGreater,
86+
}
87+
}
88+
```
89+
90+
This allows the implementation of `PartialOrd` to in most cases be as simple
91+
as
92+
```rust
93+
impl PartialOrd for Foo {
94+
fn partial_cmp(&self, other: &Self) -> PartialOrdering {
95+
self.cmp(other).to_partial()
96+
}
97+
}
98+
```
99+
This can be done automatically if/when RFC #48 or something like it is accepted
100+
and implemented.
101+
102+
# Drawbacks
103+
104+
This does add some complexity to `PartialOrd`. In addition, the more commonly
105+
used methods (`lt`, etc) may become more expensive than they would normally be
106+
if their implementations call into `partial_ord`.
107+
108+
# Alternatives
109+
110+
We could invert the default implementations and have a default implementation
111+
of `partial_cmp` in terms of `lt` and `gt`. This may slightly simplify things
112+
in current Rust, but it makes the default implementation less efficient than it
113+
should be. It would also require more work to implement `PartialOrd` once the
114+
currently planned `cmp` reform has finished as noted above.
115+
116+
`partial_cmp` could just be called `cmp`, but it seems like UFCS would need to
117+
be implemented first for that to be workrable.
118+
119+
# Unresolved questions
120+
121+
We may want to add something similar to `PartialEq` as well. I don't know what
122+
it would be called, though (maybe `partial_eq`?):
123+
```rust
124+
#[deriving(Eq)]
125+
pub enum PartialEquality {
126+
PartialEqEqual,
127+
PartialEqNotEqual,
128+
PartialEqUncomparable,
129+
}
130+
131+
pub trait PartialEq {
132+
fn partial_eq(&self, other: &Self) -> PartialEquality;
133+
134+
fn eq(&self, other: &Self) -> bool { self.partial_eq(other) == PartialEqEqual }
135+
136+
fn neq(&self, other: &Self) -> bool { self.partial_eq(other) == PartialEqNotEqual }
137+
}
138+
```

0 commit comments

Comments
 (0)