One reason why Python doesn't let you overload the boolean AND and OR operations
Recently I read Kurt Rose's DISappearing and (via
Planet Python), where Kurt noted that Python doesn't have __...__
methods that let you override boolean and
and or
operations on
your class objects. As it happens, there's a really good reason for
this, which is that Python would require a new fundamental data type
in order to make it really work.
Boolean and
and or
have the extremely valuable property of
short-circuiting evaluation, where if you write, say, 'a() and
b()
' and a()
evaluates to false, Python will not even call b()
.
Let's imagine a hypothetical world in which Python allows you to
do this overriding and the boolean operators still preserve this
short circuiting. As usual, if you write 'a and b
', this will (at
least some of the time) translate into a call to the override method
on a
, let's call it __band__
, and the __band__
method will
receive an additional argument that represents the right hand side:
class AClass: def __band__(self, right): ....
Now here is the big question: what's the type of right
in this
method?
In binary __and__
, right
is the value we get from evaluating
the right hand side expression; if you write 'a & b()
', this is
roughly the same as a.__and__(b())
. However this can't be the
case for __band__
, because that would mean no more short-circuiting;
if a
had a __band__
method, writing a and b()
would call
b()
all of the time. To preserve short-circuiting, right
has
to be some type that represents the right hand side expression in
an un-evaluated form.
However, Python has no such type today. Closures sort of come close,
but they create additional effects and do things like appear in Python
exception backtraces. This means that adding override methods for
boolean operations would require either discarding short-circuiting (and
making right
be the evaluation result) or figuring out and introducing
a new, relatively complex type in Python just to support this.
(Continuations are sort of what you'd need but I think they're not quite what you want, or at least you need a continuation that captures only the right side expression.)
The other problem of such a right
type is that you'd want to be
able to peer inside it relatively easily. After all, the entire
purpose of implementing your own __band__
method is so that you
can do something different from a plain boolean and
when the right
hand side is some special thing. If all you're going to do is:
def __band__(self, right): if not bool(self): return False else: return right.eval()
then there's not really any point in having a __band__
at all,
especially given the general complexity involved in Python as a
whole.
(This is of course not necessarily the only reason for Python to fence off boolean operations as things that you absolutely can't override. You can certainly argue that they should be inviolate and not subject to clever redefinitions simply as a matter of principle.)
|
|