# Operator Precedence/Boolean Logic

Steven D'Aprano steve at pearwood.info
Wed Jun 29 09:08:01 EDT 2016

```On Wed, 29 Jun 2016 08:21 pm, Rustom Mody wrote:

> So if we are in a link-pillow-fight here is a link
> https://mail.python.org/pipermail/python-ideas/2016-June/040780.html
> in which python-dev Nick Coghlan answers the question:
>
>> Q: ...supporting arithmetical operations (1+True==2) was a primary
>> intention, in which case my question is "why?".
>>
>> Nick: The inheritance from int meant the default behaviour was to support
>> type-promoting integer arithmetic operations in addition to bitwise
>> arithmetic.
>>
>> That changes the question from "Why support that?" to "Why do the extra
>> design, documentation and implementation work needed to prevent that?".
>>
>> The fact that "1 + True == 2" is surprising hasn't proven to be enough to
>> motivate anyone to define the precise subset of operations they want to
>> prevent, and then make the case for those restrictions as Python's native
>> behaviour.

Nick is a very senior core developer, and we would be foolish to ignore his
opinion, but that doesn't make his comments gospel.

To Nick, having 1+True return 2 is an accident of implementation, where it
is too much work to prevent it for the minimal gain it would give. And
historically, that was Guido's attitude back when Python gained a bool
type.

(Initially Python gained to pseudo-constants, True and False, set equal to 1
and 0; then in the following release it gained a built-in type bool that
subclassed int, with exactly two instances, True and False.)

But it is my argument that with (roughly) ten years of experience with us,
we can say that 1+True == 2 is not just an unfortunate accident of
implementation that we are forced to live with because nobody wants to do
the work to correct it. Rather, it is a useful and desirable feature. If I
were designing a new language from scratch, I would probably follow
Python's lead and use an int subclass for bools.

As I said before, this isn't to dispute or deny the fact that bools-as-ints
have unfortunate consequences. But they have useful consequences too, and
in my opinion they outweigh the bad ones.

If you disagree, okay, you disagree. I like broccoli and hate streaky bacon,
others feel the opposite way. I'm lucky that Python, due to historical
accident, ended up working the way I prefer. When you design your own
language, you can make it work the way you prefer.

[...]
> More significant...
>
> Steven D'Aprano wrote:
>
>> So we have falsey values:

Note that the question of truthy/falsey duck-typed bools is independent of
whether bools are abstract flags or concrete ints. A language could:

- have a dedicated, abstract bool type, like Pascal does;

- completely do without a dedicated bool type, and just have truthy/falsey
values, like Python 1.5 did;

- allow all values to be treated as truthy/falsey values, but have a
concrete (int-subclass) bool type as the canonical true/false, like Python
2 & 3 does;

- allow all values to be treated as truthy/falsey values, but have an
abstract bool type as the canonical true/false, like Javascript does.

So the question of truthy/falsey values is orthogonal to the question of
whether bool should inherit from int.

> In short,
> - Steven hints that empty/non-empty is some sort of *generic* property of
> data structures - Chris strengthens that to include types outside of
> builtins -- Red-Black trees - Marko (thankfully adding the I dont like)
> connects emptiness to the dunder __bool__

It's not just a hint. Python has a convention that empty collections should
be treated as falsey; likewise empty sequences; likewise "empty" numbers.
And non-empty ones should be treated as truthy. This is built into the way
the interpreter decides whether something is truthy or falsey.

Given:

if spam: ...
else: ...

Python decides which branch to take as follows:

- if spam has a __len__ method, and spam.__len__() returns 0, then spam is
falsey and the `else` branch is taken;

- if spam.__len__() returns a non-zero number, then spam is truthy and the
`if` branch is taken;

- otherwise, if spam has a __nonzero__ method (__bool__ in Python 3), if it
returns a falsey value, then spam is falsey;

- but if it returns a truthy value, then spam is truthy;

- and if spam has neither a __len__ nor a __nonzero__ / __bool__ method,
then by default it is truthy.

> So here's some questions for the bool-fans
>
> Please show me how we would define __bool__ for
>
> 1. Graphs -- the kind mathematicians define with "Let G =(V,E) be a
> graph..."

I would make the empty graph (zero nodes) falsey, and non-empty graphs (one
or more nodes) truthy.

> 2. Automata which in a way are special kinds of graphs

As above.

> 3. Regular Expressions which mathematically are related to automata
>   And pragmatically are (more) present in python than the first two

Can you even have an empty regular expression? What does it match? Possibly
nothing at all.

Ideally, I would have the empty regular expression be falsey, and all others
truthy, but I wouldn't be too upset if all regexes were True.

--
Steven
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.

```