Unravelling boolean operations
As part of my series on Python's syntactic sugar, I am going to cover boolean operations: a or b
and a and b
.
The semantics
A key thing to know about or
and and
is that they short-circuit. What that means is that if just the first argument is enough to know the outcome of the expression then the second argument is never evaluated. Compare that to something like addition where both the left-hand side and right-hand side of +
are evaluated no matter what.
In the case of a or b
, if a
is true then a
is the result of the expression since it's a foregone conclusion that the overall or
expression has a true value. If a
is false then we evaluate b
and return its value regardless of what b
is since whatever its truthiness is represents what the or
expression's truthiness is. This short-circuiting opens up some niceties like providing a default value, e.g. a or "default"
. To help visualize this, if we ignore a or b
as an expression and treat it as result = a or b
, then we can unravel this all to:
For a and b
, if a
is false then it's immediately returned since there's no need to know the value of b
as it's a foregone conclusion; the and
expression is going to be false. If a
is true, though, then the value of b
is the result of the expression. For result = a and b
, we can unravel that to:
The unravelled syntax
We can actually simplify/shrink our statement examples thanks to assignment expressions. For instance, result = a or b
can become:
The equivalent for a and b
is:
The problem with these examples is they still turn an expression into a statement. For instance, if you had spam(a or b)
then you couldn't use the example I used above.
But if we add in conditional expressions, we can actually convert this approach to an expression! For a or b
, we can make it be temp if (temp := a) else b
; for a and b
, it can be temp if not (temp := a) else b
(historical footnotes about conditional expressions: Guido polled the audience at PyCon US 2005 over the various syntax proposals for conditional expressions, and if you read his pronouncement email you will notice people hating on him for syntax decisions like assignment expressions that ultimately caused Guido to retire as BDFL had been going on for decades).
Now some astute readers might raise an objection over my claim that temp if (temp := a) else b
is equivalent to a or b
because there is now a temp
variable in existence. This is true, but I don't think it's much of a concern because CPython itself cheats like this somewhat. 😄
CPython's cheating at variables
Have you ever looked at the local variables that exist when you use a list comprehension?
Notice the .0
variable? That's a temp variable that Python creates to hold the iterator of the for
loop. This is an implementation detail that most people never care about since the name isn't valid Python syntax. But for my purposes it shows that using a temp variable that the user isn't aware of is not unheard of. It also shows that the compiler can use names that users will never accidentally clash with, and some transpiler could always make sure to choose names that the user doesn't use in any way. In other words, I don't think I'm cheating here in a way that matters. 😉