Re: Overloading the comparison operator

Tim Peters (tim@ksr.com)
Wed, 25 May 94 03:13:21 -0400

Rather than introduce a new __equal__ method with special rules, I'd
rather see Python move to a less exception-laden model for overloading in
general. E.g., today you can get "class_instance + tuple" to work, but
not "class_instance - tuple"; "class_instance == string" is accepted, but
doesn't go thru __coerce__ or __cmp__ even if both the latter are class
methods; OTOH, "class_instance << string" goes thru __coerce__ and
__lshift__, and "class_instance / class_instance" goes thru __coerce__
and __div__, but "class_instance < class_instance" goes thru __cmp__ but
not __coerce__.

I think I've done about as much operator overloading in Python as anyone
by now, and the rules are hard to predict; I think Guido made a small
mistake in presuming that, e.g., "<<" will only be used for "numeric"
types, and "[]" only for "mapping" types, etc. Would be easier on the
brain if, e.g.,

class_instance any_binary_operator anything_at_all

always "tried to work", and called __coerce__ first if it's a
class_instance or anything_at_all method, but didn't gripe if __coerce__
doesn't exist.

OTOH, it's hard to think of a rational set of rules that's compatible
with all the dark corners in the current rules!

That wouldn't solve your "== and != are OK, but no other relational
operators" problem, but __eq__, __ne__, __lt__, __le__, __gt__, __ge__
methods would <wink>. E.g., I might want to define a set type that
supports a "subset" operator (<=) but not a "includes as a subset"
operator (>=).

The current scheme assumes too much about what the user _intends_ the
operator symbols to mean, sometimes demanding coercions where they may
not be needed or wanted, decreeing that some combinations of types will
not be allowed to work no matter what you do, and not invoking __coerce__
in some contexts where you might want it. In a sense, the language is
trying to be very helpful, but won't _stop_ <wink>.

> As I understand it, existing code generally does not expect
> comparisons to raise exceptions.

This is due to two things:

1) In the base language (i.e., ignoring the possiblity of __cmp__
methods),

object1 relational_operator object2

is defined for all combinations of object types and relational
operators. _I_ think this is a feature. E.g., if I'm doing a binary
search on a sorted list of objects, it makes no difference at all what
a relational_operator returns, so long as it's consistent within a
run ("consistent" means things like "if '<' returns true, '>=' returns
false", "if a==b and b==c, then a==c", and "exactly one of a<b, a==b,
a>b returns true" -- & the base-language comparisons do satisfy
those).

2) This note in the reference manual:

> Implementation note: due to limitations in the interpreter, exceptions
> raised by comparisons are ignored, and the objects will be considered
> equal in this case.

If you take away my ability to make a sorted list out of objects from
your class, I think you've taken away something I sometimes have good use
for, but I don't think it therefore follows that you shouldn't be allowed
to do so. E.g., if I like your objects so much that I just can't live
without storing them in sorted lists, I can inherit from your class (or
embed it) and define my own __cmp__ on them. So I don't object to what
you're after! Just hoping it can be made more general.

agreeably y'rs - tim

Tim Peters tim@ksr.com
not speaking for Kendall Square Research Corp