# [Python-3000] ABC for Inequalities

Guido van Rossum guido at python.org
Tue Feb 12 05:41:55 CET 2008

```On Feb 11, 2008 7:31 PM, Raymond Hettinger <python at rcn.com> wrote:
> [GvR]
> > Hold on. We went down that road quite a bit and then discovered it
> > wasn't going to work.
>
> I figured that it was missing for a reason.
>
> > The problem is that if you have two instance x,
> > y such that isinstance(x, TotalOrdering) and isinstance(y,
> > TotalOrdering) you still don't know if x < y is defined. (For example,
> > if x is a string and y is a number.)
>
> So, ordering only makes sense when "other" is known to be
> of the same type as "self".

No, that's too far in the other direction. E.g. two instances of Real
but of different implementations should still be comparable. (Though I
expect there's some higher math involved to prove this for all reals.
:-)

> > There's a useful definition in there somewhere but
> > it's elusive. We'll eventually figure it out.
>
> I hope so. I'm less interested in the mixin and more interested in
> a way for a class to have a way to tell you whether it is sortable.
> Right now, the presence or absence of __le__ doesn't tell
> you much.

Yeah, this is one area where a leap of faith (a.k.a. duck typing :-)
may still be the best approach.

I think you can probably get something that is reasonable given the
kind of assumptions that prevail in an ABC world by having a
"Sortable" metaclass (itself a subclass of ABCMeta) with the implied
semantics that objects x and y can be sorted if the nearest common
ancestor of x.__class__ and y.__class__ is an instance of Sortable.
E.g.

class S(metaclass=Sortable): ...

class S0(S):
def __lt__(self, other): ...
def __le__(self, other): ...
...etc...

class S1(S0): ...

class S2(S0): ...

x = S1()
y = S2()

Now x<y should work: the nearest common ancestor of S1 and S2 is S0,
which is a subclass of S, which is an instance of Sortable. (If S is
an instance of Sortable, so is S0 -- that's how metaclasses are
inherited.)

But I'm not sure this is worth it; we don't have an easy way to add
this to an argument annotation, since the argument annotations are
(usually) assumed to be type expressions so that f(x:T) means
isinstance(x,T) -- but here we want to express isinstance(x.__class__,
Sortable). The best I can think of is to say that if the annotation is
a lambda (not just any callable, since classes are callable) it must
evaluate to true when called on the actual argument: then we'd write
f(x: (lambda x: isinstance(x.__class__, Sortable))). Very ugly, but
could of course be abbreviated with a suitable helper function to f(x:
metaclass_is(Sortable)).

PS. "Sortable" is perhaps not the best name, as one would perhaps
think that a list of numbers is sortable because it has a .sort()
method... Maybe Orderable or Ordered or TotallyOrdered?

--