Why keep identity-based equality comparison?

Noam Raphael spam.noam at gmail.com
Sat Jan 14 16:38:35 EST 2006

Mike Meyer wrote:
> spam.noam at gmail.com writes:
 >>    return a == b
 >>except TypeError:
 >>    return a is b
> This isn't "easy". It's an ugly hack you have to use everytime you
> want to iterate through a heterogenous set doing equality tests.

I wouldn't define this as an "ugly hack". These are four simple line, 
which state clearly and precisely what you mean, and always work. I have 
seen ugly hacks in my life, and they don't look like this.
> You're replacing "false" with an "emphathetic false", that *all*
> containers to change for the worse to deal with it.
I don't see how they change for the worse if they have exactly the same 
functionality and a few added lines of implementation.
>>Also, Mike said that you'll need an idlist object too - and I think
>>he's right and that there's nothing wrong with it.
> Except that we now need four versions of internal data structures,
> instead of two: list, tuple, idlist, idtuple; set, idset, frozenset,
> frozenidset, and so on. What's wrong with this is that it's ugly.

Again, "ugly" is a personal definition. I may call this "explicitness". 
By the way, what's the "and so on" - I think that these are the only 
built-in containers.
>>Note that while you
>>can easily define the current == behaviour using the proposed
>>behaviour, you can't define the proposed behaviour using the current
> Yes you can, and it's even easy. All you have to do is use custom
> classes that raise an exception if they don't

You can't create a general container with my proposed == behaviour. 
That's what I meant.
>>Also note that using the current behaviour, you can't easily
>>treat objects that do define a meaningful value comparison, by
> Yes you can. Just use the "is" operator.

Sorry, I wasn't clear enough. In "treating" I meant how containers treat 
the objects they contain. For example, you can't easily map a value to a 
specific instance of a list - dict only lets you map a value to a 
specific *value* of a list. Another example - you can't search for a 
specific list object in another list.
> Note that this behavior also has the *highly* pecular behavior that a
> doesn't necessarily equal a by default.

Again, "peculiar" is your aesthethic sense. I would like to hear 
objections based on use cases that are objectively made more difficult. 
Anyway, I don't see why someone should even try checking if "a==a", and 
if someone does, the exception can say "this type doesn't support value 
comparison. Use the "is" operator".
> I will point out why your example usages aren't really usefull if
> you'll repeat your post with newlines.
Here they are:

* Things like "Decimal(3.0) == 3.0" will make more sense (raise an
exception which explains that decimals should not be compared to
floats, instead of returning False).
* You won't be able to use objects as keys, expecting them to be
compared by value, and causing a bug when they don't. I recently wrote
a sort-of OCR program, which contains a mapping from a numarray array
of bits to a character (the array is the pixel-image of the char).
Everything seemed to work, but the program didn't recognize any
characters. I discovered that the reason was that arrays are hashed
according to their identity, which is a thing I had to guess. If
default == operator were not defined, I would simply get a TypeError
* It is more forward compatible - when it is discovered that two types
can sensibly be compared, the comparison can be defined, without
changing an existing behaviour which doesn't raise an exception.

The third example applies to the Decimal==float use case, and for every 
type that currently has the default identity-based comparison and that 
may benefit from a value-based comparison. Take the class

class Circle(object):
     def __init__(self, center, radius):
         self.center = center
         self.radius = radius

Currently, it's equal only to itself. You may decide to define an 
equality operator which checks whether both the center and the radius 
are the same, but since you already have a default equality operator, 
that change would break backwards-compatibility.


More information about the Python-list mailing list