Excluding the empty range case, handling Ord
values is pretty straightforward. However, implementing range comparison with only PartialOrd
is non-trivial.
As a simple non-total partial order, we can use the relation “divides”. For instance, 2 divides 6 and 3 divides 6, but 4 does not divide 6. This is a partial order because:
- reflexivity: for any natural integer (including 0)
x
, x
divides x
- antisymmetry: for any natural integers
x
and y
, if x
divides y
and y
divides x
, then x
= y
(it follows naturally from the fact that, if x
divides y
, then x
≤ y
)
- transitivity: for any natural integers
x
, y
and z
, if x
divides y
and y
divides z
, then x
divides z
However, this is not a total order, because 4 does not divide 6 and 6 does not divide 4.
Now, given x
, y
and z
that implement the PartialOrd
describe above, what should the relation between x
and y..z
be?
Note that, by definition, y..z
contains all a
such that verify: x
divides a
and a
divides z
. Let us consider a few cases:
- with 4 and 2..8 : since 2 divides 4 and 4 divides 8, the result is clearly
Inside
- with 2 and 4..8 : since 2 divides 4, the result is clearly
Below
- with 8 and 2..4 : since 4 divides 8, the result is clear
Above
- with 3 and 2..8 : since 3 is not in the interval 2..8, it should not be considered
Inside
for this order
- with 3 and 4..8 : since 3 does not divide any element of 4..8, we cannot say that it is
Below
for this order
- with 9 and 2..4 : since no element of 2..4 divide 9, we cannot say that it is
Above
for this order
Now, the mathematical definition is valid when y
divides z
. But Rust's range types do not enforce this, so we have an additional case to handle:
- with 4 and 2..7 : 2 does not divide 7, so it is not covered by the definition
And finally, #6 applies as well:
- with 4 and 8..2 : the interval is empty, so comparison is meaningless
Cases 1, 2, 3 are open-and-shut. I think 4 through 8 should return None
as per PartialOrd
semantics. 8 is more debatable.