Expression can be simplified on list
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Thu Sep 29 04:14:32 EDT 2016
On Thursday 29 September 2016 16:47, Rustom Mody wrote:
> On Thursday, September 15, 2016 at 1:43:05 AM UTC+5:30, Terry Reedy wrote:
[...]
>> Python make no such nonsense claim. By default, Python objects are truthy.
>>
>> >>> bool(object())
>> True
>>
>> Because True is the default, object need not and at least in CPython
>> does not have a __bool__ (or __len__) method. Classes with no falsey
>> objects, such as functions, generators, and codes, need not do anything
>> either. In the absence of an override function, the internal bool code
>> returns True.
>>
> Not sure what you are trying to say Terry...
> Your English suggests you disagree with me
> Your example is exactly what I am saying; if a type has a behavior in which
> all values are always True (true-ish) its a rather strange kind of
> bool-nature.
In what way do you think it is "rather strange"?
This suggests that you believe that all types must have distinct truthy values
and falsey values, or else that type's values shouldn't be usable in a truth
context at all. Is that what you mean?
My view is somewhat different. I see truthiness as an abstraction. Like all
abstractions, it may leak -- I make no apologies for the fact that Python
doesn't have syntactic support for Keene three-value logic or other multi-
valued logics, nor do I make any apologies for the (hypothetical, rare) object
which doesn't fit well into this truthy abstraction. All abstractions leak
somewhere, and this abstraction is proven to work well in practice, not
withstanding the rare glitch.
What is this truthiness abstraction? It is the difference between "something"
and "nothing".
Values which represent nothing, e.g.:
- None
- numeric zero: 0, 0.0, 0j, Decimal(0) etc
- empty strings u'', ''
- empty containers [], (), {} etc.
are treated as falsey. And values that represent something, e.g.:
- numbers other than zero
- strings other than the empty string
- non-empty containers
are treated as truthy. On this basis, by default objects should be considered
truthy: objects represent something rather than nothing:
- a module object is something;
- a function object is something;
- a HTTPServer object is something;
and so all of these things -- modules, functions, HTTPServers -- should default
to always truthy unless the programmer specifically programs them otherwise.
A few pre-emptive responses to possible objections:
Objection: There's only one sort of nothing.
Response: There are different kinds of nothing. "I have no shoes" is not the
same as "I have no feet". The hole in a donut is not the same as a hole in the
ground or an electron hole in a crystal lattice. The set of ideas held by
somebody who has no idea is not the same kind of nothingness as the nothingness
in a vacuum.
Objection: But nothing isn't nothing, it's something!
Response: You are committing the fallacy of reification. Just because you can
give a name to a concept doesn't make the concept a thing. "Cold" is not a
thing, it is just the absence of heat, "death" is the absence of life,
"stillness" is the absence of motion, and "nothing" is the absence of things,
not a thing itself. That's why there are different kinds of nothing -- it
depends which things get counted.
Objection: Even the vacuum is not empty! It is filled with a sea of virtual
particles and anti-particles and zero-point energy.
Response: I've studied quantum mechanics and particle physics too. You're very
clever. Do I really have to answer this one?
Objection: Yes.
Response: Okay.
The existence of zero-point energy is very interesting, but it has no relevance
to the topic we're discussing. In practical terms, most "zeroes" are relative
measures, not absolute. For an electrical analogy, think of electrical
potential: what matters is the potential difference, not the actual potential.
There's no current flowing between two points both at the same potential
energy. Similarly, we don't usually care about the *absolute* presence or
absence of things, but relative to some quantity or substance. A hole in the
ground is filled with air, or sometimes water, but we care only about the lack
of soil in the hole.
Objections: Empty containers aren't nothing, they are themselves a thing. An
empty egg carton is still an empty carton, even if there are no eggs in it.
Response: Indeed.
Nevertheless, the language designer gets to choose the specific model of
truthiness the language uses. In the opinion of the Python designer GvR, it is
more useful to care about the *content* of the container than the container
itself in a truth context. Some languages make other choices. If you don't like
Python's choice, you are free to:
- suck it up and live with it;
- fork Python and give the fork your preferred semantics;
- use another language which is a closer fit to your preferences;
- use your own container types with your preferred semantics;
- complain bitterly about it on your blog, Facebook wall, mailing lists etc.;
- buy an automatic weapon and make GvR pay for disagreeing with you;
etc. although some of these choices are better than others.
[...]
> Sure one can always (ok usually) avoid a bug in a system by not using the
> feature that calls up the bug. Are you suggesting that that makes the bug
> non-exist?
You haven't demonstrated that the existence of a feature is a bug.
> In more detail:
> - If user/programmer defines a new type
> - Which has no dunder bool
> - Which has no dunder len
> - Which has no ... (all the other things like len that can make for a
> non-trivial bool behavior)
> - And then uses a value of that type in a non-trivial bool-consuming position
> such as the condition of an if/while etc
then they get the default behaviour, just as they get the default behaviour if
they call str() or repr() on their object without defining their own __str__ or
__repr__ methods, or if you call == without providing a custom __eq__ method.
> There's a very good chance that bool-usage is buggy
I doubt it.
> In more mundane terms, dunder bool defaulting to true is about as useful
> as if it defaulted to
> 2*random.random()
No, not all. There is a consistent model and predicable effects from defaulting
to true. There is no consistent model from defaulting to 2*random().
(Although, since that is **nearly always** a truthy value, it probably makes no
practical difference: the object will be falsey only about 1 time in 2**60 or
2**61).
> Why not default it in the way that AttributeError/NameError/TypeError etc
> are raised?
Because that would be less useful and more annoying.
There are a set of behaviours which nearly all objects should define, and which
are nearly always the same (or at least have a sensible default):
__getattribute__
__getattr__
__setattr__
__delattr__
__str__
__repr__
__eq__
__ne__
__hash__
__bool__
etc. Since the behaviour is nearly always the same, it makes sense to move that
behaviour into the base class object(), and let the exceptional cases be
exceptional, rather than require everybody to write the same piece of code over
and over and over again.
--
Steven
git gets easier once you get the basic idea that branches are homeomorphic
endofunctors mapping submanifolds of a Hilbert space.
More information about the Python-list
mailing list