Operator Precedence/Boolean Logic

Steven D'Aprano steve at pearwood.info
Sat Jul 16 06:16:49 EDT 2016


On Sat, 16 Jul 2016 03:48 pm, Rustom Mody wrote:

> On Thursday, June 30, 2016 at 10:52:50 PM UTC+5:30, Steven D'Aprano wrote:
>> Okay, if you think that automata cannot be empty, I'll accept that. In
>> that case, then I'll change my answer and say that __bool__ for automata
>> should simply return True. All automata should be truthy.
>> 
> 
> I am not sure with what tone of voice you are saying that

A standard, non-sarcastic tone of voice.


> If ... “return True” is about as good -- ie useful -- as (say)
> 
> def __bool__(self):
>   from random import random
>   return int(2*random())
> 
> then I think we agree

No, I don't agree with that. "Emptiness" or "zeroness" or "falsity" doesn't
necessarily make sense for every single kind of object. If we were
modelling (say) Employees, then I would probably model all Employees as
truthy. That's easy to do: all objects are truthy by default, so I don't
have to do a thing.

If there is some concept of an "empty/null/do-nothing" automata, then I
would consider making such null automata falsey. But I'm no sure I would
care enough to bother. For example, functions are all truthy, even
do-nothing functions.


> But then there is a well-established behavior pattern in python
> captured by the contexts that raise AttributeError/NameError/TypeError etc
> viz For things that are undefined we are told politely they are undefined
> 
> IOW Why say something is useless and define it rather than just leave
> undefined something that is ill-defined.

You are forgetting that you're not necessarily encountering automata in a
context where you are expecting an automata and nothing else:

x = Turing_Machine(foo)
if x:
    x.run()
else:
    x.blibbet()


You may encounter one in code that is expecting arbitrary objects, without
caring whether they are floats or HTTPServers or re.MatchObjects or
automata or Employees or something else:

for obj in bunch_of_objects:
    if obj:
        turn_left()
    else:
        turn_right()


There's an argument in favour of Pascal-style "true booleans" that require
you to use True and False *only* in boolean contexts; and there's an
argument in favour of Python's truthiness where any object can duck-type in
a bool context; but what doesn't make sense is to have *some* objects be
usable as true/false, forcing you to write code like this everywhere you
have to deal with arbitrary truthy objects:


for obj in bunch_of_objects:
    try:
        # Okay for collections, sequences, ints, floats, None, 
        # FooManagers, HttpServers, Dogs, Horses, Pizzashops, etc.
        flag = bool(obj)
    except TypeError:
        # But not okay for Automata, Employees, Cats, PrintFormatters, etc.
        flag = True  # default to true, say
    if flag:
        turn_left()
    else:
        turn_right()


That's just awful language design. You should have either two booleans only,
or all objects should be booleans.



> If on the other hand you are giving that “return True”as a serious useful
> definition?

Sure. An automata is an object, and by default, all objects are "something"
and hence truthy. That's the "no-brainer" answer, it requires no
justification at all. If you think the answer should be something else,
*that* is what needs justification. Why shouldn't it be truthy?

 
> If both you and Chris tripped up on a right definition of an “empty”
> automaton and regex respectively, I believe it demonstrates that getting
> boolishness for an arbitrary type right is at least non-trivial. [FWIW My
> belief: In general its nonsensical]

Firstly, I disagree that I tripped up on anything. You haven't given any
reason to think that Automata objects shouldn't be truthy, and even if you
do, isn't that just a matter of opinion?

But in general, deciding on whether an arbitrary object should be truthy or
falsey is not hard, and most of the time you don't have to do a thing to
get the right behaviour.

- Does the object represent a collection or sequence? If so, then the right
behaviour is to delegate to `len(obj) != 0`.

- Does the object represent a number? If so, then the right behaviour is to
delegate to `obj != 0`.

- Does the object represent (in some sense) nothing rather than something?
That is, is it a reification of "there's nothing here"? E.g. something like
None in Python, null/nil pointers, Void, or Undefined. Then it should be
falsey.

- Otherwise, it represents something rather than nothing, and unless you
have pressing reason to do otherwise, it should be truthy.




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




More information about the Python-list mailing list