Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upShould PartialOrd and Ord impls be equivalent? #41270
Comments
TimNN
added
the
T-libs
label
Apr 13, 2017
This comment has been minimized.
This comment has been minimized.
|
For the record, the PR that changed this is #39538. |
This comment has been minimized.
This comment has been minimized.
|
For concreteness, on play.rust-lang.org, the following code succeeds under stable, and panics on nightly. It defines a partially ordered use std::cmp::Ordering;
#[derive(Debug, Eq, PartialEq, Ord, Copy, Clone)]
struct Coord {
x: u32,
y: u32,
}
impl PartialOrd for Coord {
fn partial_cmp(&self, other: &Coord) -> Option<Ordering> {
if self.x == other.x && self.y == other.y { Some(Ordering::Equal) }
else if self.x <= other.x && self.y <= other.y { Some(Ordering::Less) }
else if self.x >= other.x && self.y >= other.y { Some(Ordering::Greater) }
else { None }
}
}
fn main() {
let c1 = Coord { x: 1, y: 2 };
let c2 = Coord { x: 2, y: 1 };
let mut v1 = vec![c1, c2];
let mut v2 = vec![c2, c1];
v1.sort();
v2.sort();
assert_eq!(v1, v2);
} |
TimNN
added
the
I-nominated
label
Apr 13, 2017
This comment has been minimized.
This comment has been minimized.
|
Nominating since this can probably be classified as either a breaking change or a regression. |
This comment has been minimized.
This comment has been minimized.
|
Ord says Trait for types that form a total order. and defines this in terms of the comparison operators. partial_cmp says This method returns an ordering between self and other values if one exists.; and the ordering does exist if the type is This relationship should be clearer in the docs. |
This comment has been minimized.
This comment has been minimized.
|
If this interpretation is correct, this line from the
For what it is worth, I think it is totally reasonable to allow Can you say why it is important to unify the two, when both exist? The only reason I can see is that the assumption has existed for a while, and someone would have to audit the code for |
This comment has been minimized.
This comment has been minimized.
|
Also, the requirement that |
This comment has been minimized.
This comment has been minimized.
It's also totally reasonable that the assertion in your example program's assertion fails on nightly. PartialOrd's docs say it is “Trait for values that can be compared for a sort-order.” and your vector is being sorted in a way that is consistent with PartialOrd. It is unreasonable if
Yes, the design doesn't really take anything more than floats into account. I don't think PartialOrd is designed to be useful on its own. It's a crutch for floating point numbers, and a way to separate them out from the regular totally ordered types. Floats are one example of a type that could implement a total order, different from its partial order, but the trait |
This comment has been minimized.
This comment has been minimized.
Yup, I think both are reasonable. I was reacting to your claim that it is unreasonable any other way. :)
I agree that it can be confusing. However, it gives you access to the < operator because Can I propose an alternate, less confusing design if |
This comment has been minimized.
This comment has been minimized.
|
Derives are recipes that are good for common cases but not for every case. It's often wrong to request derive(Ord) when implementing PartialOrd manually — and that could be a warning. |
This comment has been minimized.
This comment has been minimized.
|
If we imagine that |
This comment has been minimized.
This comment has been minimized.
|
I think it should be the |
This comment has been minimized.
This comment has been minimized.
|
The libs team discussed this at triage yesterday and we believe that this issue is the same as #40192, which we closed with the intention of "PartialOrd must behave the same as Ord, if implemented". It sounds like though we definitely need to update the docs! @frankmcsherry out disposition was to stay the current course (while updating docs), but have you found it difficult to update the code you have locally? If that takes awhile we don't mind considering backing out the change temporarily to reevaluate. One reason we're tempted to continue to require that Ord/PartialOrd are equivalent is along the lines of what @bluss mentioned above, different parts of the standard library will react differently if they behave differently. The intent is that they're used interchangeable on |
This comment has been minimized.
This comment has been minimized.
|
I'm planning on removing I think the main frustrating thing is going to be auditing code to make sure I don't use Edit: I have no idea if it is a breaking change, but adding a default implementation for |
This comment has been minimized.
This comment has been minimized.
|
Ok in that case I believe that the outstanding issue here to be fixed is to clarify the documentation of @frankmcsherry if you find it difficult to upgrade though please let us know! |
alexcrichton
added
the
T-doc
label
Apr 26, 2017
This comment has been minimized.
This comment has been minimized.
|
I'll let everyone know, not to worry. ;) |
brson
added
E-easy
P-medium
labels
May 4, 2017
This comment has been minimized.
This comment has been minimized.
|
Next step here is to update the documentation for both PartialOrd and Ord to indicate that the two must agree on the ordering of any types they are implemented on. |
This comment has been minimized.
This comment has been minimized.
|
What about the relationship between Edit: wrong link. |
This comment has been minimized.
This comment has been minimized.
|
@Rufflewind Which example? There are a lot of code in that page. |
This comment has been minimized.
This comment has been minimized.
|
@kennytm My link was incorrect. Here’s the correct one: https://doc.rust-lang.org/std/collections/binary_heap/#examples (“This is a larger example that implements Dijkstra's algorithm to solve the shortest path problem on a directed graph.”) |
This comment has been minimized.
This comment has been minimized.
|
@Rufflewind That's a great find in the Yes, the answer is that More concretely, here's what is I suggest changing:
Anything else I'm missing here? @brson? |
This comment has been minimized.
This comment has been minimized.
I think Eq can still be derived since it has no methods. |
frankmcsherry commentedApr 13, 2017
•
edited
Nightly introduces a change that alters the behavior of sorting, by using the
PartialOrdmethodslt,leand such, rather thanOrdscmpmethod.This has implications for me, on account of I am a weirdo with types that implement both
PartialOrdandOrd, with the property thatOrdis a strict refinement ofPartialOrd. That is, wheneverpartial_cmpreturns a non-Nonevalue thencmpreturns the same value, but there are incomparable elements of the partial order that are ordered byOrd. This sounds like a mess, but is important for doing things like efficient deduplication (viasort(), dedup()). For example, I have pairs of integers that are partially ordered (via product order), and I need to be able to deduplicate them.I think this is a "breaking change" in that code that previously did one thing now does another thing. It may be that it is intended, and that all implementations of
PartialOrdnot equivalent to theirOrdimplementation were in error and get no love, but (i) it would be great to have someone actually state that, and (ii) thePartialOrddocs could use some sprucing up (they currently say thatPartialOrdis for defining sort orders, which is ...).I can fix all of my code, by moving all the
PartialOrdfunctionality into theLatticetrait I already have, but I don't see why anOrdimplementation should imply a totalPartialOrdimplementation (you should add a default implementation ofcmpthat unwrapspartial_cmpin that case).Edit bluss pointed me at #12517 which discusses the naming and stuff, but I couldn't see that the discussion came to a conclusion on whether
PartialOrdmust be equivalent toOrdwhen it exists.