I'm afraid you are mistaken there. *By design*, Python allows shadowing
and monkey-patching of built-ins. (Although not quite to the same degree
as Ruby, and thank goodness!)
Yes, I understand that. You still haven't explained why this behavior
is correct in this particular situation. Arguing from the position
of, "What Python does must be correct" isn't a valid tactic, I'm
afraid.
It's useful for the same reason that shadowing any other builtin is
useful. id() isn't special enough to complicate the simple, and
effective, execution model just to satisfy philosophers.
If overriding id() is useful, then overriding 'is' must be useful
too. Python is still broken. Unless you can prove the two operations
shouldn't be logically equivalent (and you don't), you can't
meaningfully argue for different semantics for them. You still end up
with a broken language either way.
They are not *logically* equivalent. First you have to define what you
mean by identity, then you have to define what you mean by an ID, and
then you have to decide whether or not to enforce the rule that identity
and IDs are 1:1 or not, and if so, under what circumstances.
You're going to have to explain the value of an "ID" that's not 1:1
with an object's identity, for at least the object's lifecycle, for a
programmer. If you can't come up with a useful case, then you haven't
said anything of merit.
Plainly, to show they're not logically equivalent, you need to explain
why the guarantee provided by id() is improper. Then, you need to
generalize it to all programming languages. Python's concept of
identity is not unique nor special. It uses the exact same rules as C+
+, C#, Java, and many other languages.
My library
card ID may, by coincidence, match your drivers licence ID. Doesn't mean
we're the same person.
I don't know why you even remotely think this is relevant. All it
does is further demonstrate that you don't understand the object-
oriented concept of identity at all. Comparing library IDs and
drivers license IDs is an improper operation. Languages that can have
multiple IDs, possibly overlapping, /do/ disallow such idiocy.
identities. The Borg design pattern, for example, would be an excellent
candidate for ID:identity being treated as many-to-one.
How would inheritance work if I did that?
Even if you decide that treating IDs as 1:1 is the only thing that makes
sense in your philosophy, in practice that does not hold for Python. IDs
may be reused by Python.
They may be reused in all languages I can think of. They're only
unique for the lifetime of the object, because that's all we need as
programmers.
There are circumstances where different objects
get the same ID. Hence, comparing IDs is not equivalent to identity
testing.
Two objects only get the same ID if one of the objects is dead. The
results of such an comparison are obviously meaningless. Some
runtimes even try very hard to prevent you from doing such silly
things.
But I was actually referring to something more fundamental than that. The
statement "a is b" is a *direct* statement of identity. "John is my
father." "id(a) == id(b)" is *indirect*: "The only child of John's
grandfather is the parent of the mother-in-law of my sister-in-law" sort
of thing. (Excuse me if I got the relationships mixed up.)
Again, the fact that you somehow think this absurd family tree is
relevant only shows you're fundamentally confused about what object
oriented identity means. That's rather depressing, seeing as I've
given you a link to the definition.
In a mathematical sense, you're saying that given f(x) = x+2, using
f(x) is somehow more "direct" (whatever the hell that even means) than
using 'x+2'. That's just not true. We freely and openly interchange
them all the time doing mathematics. Programming is no different.
It is broken in the sense that "id(a) == id(b)" is to be treated as
equivalent to "a is b". The above example demonstrates that you CANNOT
treat them as equivalent.
They give different results, yes, and that's unfortunate. However, my
code clearly demonstrates they are logically equivalent operations:
the temporaries have different addresses in these cases. Both
expressions return the correct answer based on their inputs.
Since there are side-effects involved here, you cannot simply compare
the results and conclude they are different. You must account for the
side-effects, and when you do, then we conclude they have the same
semantics.
Solution to *what problem*?
This confusion that many people have over what 'is' does, including
yourself.
An address is an identifier: a number that I can use to access a
value[1].
Then by your own definition, Python's id() does not return an address,
since you cannot use it to access a value.
The fact Python lacks explicit dereferencing doesn't change the fact
that id() returns an address. Replace 'can' with 'could' or 'could
potentially' or the whole phrase with 'represents' if you wish. It's
a rather pointless thing to quibble over.
Would you call the result of casting a C pointer to an int an
address? If so, you must call the result of id() an address as well--
you can't dereference either of them. If not, then you need to
provide an alternate name for the result of casting a C pointer to an
int.
Adam