PEP 285: Adding a bool type

Alex Martelli aleax at aleax.it
Mon Apr 1 15:01:43 EST 2002


Martin v. Loewis wrote:
        ...
>> > Programmers that are used to booleans from previous
>> > languages might well find their lifes easier. Even people that you
>> 
>> In the same sense as they might well find their lifes easier if suddenly
>> they had to start decorating their Python programs with deuced braces
>> or BEGIN/END to indicate block structure -- they might find the
>> familiarity comforting.
> 
> Nah, that is hardly the same thing. With the PEP, nobody *has* to do
> anything; existing programs will continue to work just fine (with very

"if suddenly they _were allowed_ to start decorating", etc, then -- optional
BEGIN/END rather than mandatory.  "more than one way"...?

> very few exceptions). If people want to return 0 when they mean False
> - fine.

_Mostly_ fine... "with very few exceptions" -- sporadic breakage.


>> I think teaching this as alternate ways of *spelling* equal (but
>> distinct: ==, and essentially interchangeable in use, but NOT 'is')
>> values will be the least of evils.
> 
> I disagree. Somebody could use the language (with the change) and
> believe booleans are completely unrelated to numbers, and would rarely
> find this view incorrect - at which time you'll need to explain that
> booleans interact with numbers in a certain way.

Somebody could use the language under all sort of weird misconceptions,
as shown by reasonably frequent questions both here and on python-help
by people who've been using the language for quite a while and still
display some fundamental misunderstandings.  My preference when teaching
is not to encourage such misconceptions "for simplicity": experience shows
that such oversimplifications, meant to be "stepping stones" towards some
better future understanding, all too often end up as millstones 
metaphorically around students' necks.

It's best for what one's teaching to BE simple, rather than to try to make 
it APPEAR simple by hiding complications.  If complications *are* there (be 
it for good and sufficient reasons, or not), students had better be warned
(rather than waste hours "debugging" an isinstance(x, int) before being told
that, oh btw, bools ARE int...).


>> Exactly the same set of objects (plus the new object False, that's ==0
>> anyway and can be used just about wherever 0 can be)
> 
> While it is true that False can be used everywhere, it doesn't mean it
> should be. Use booleans if you want to express the value of a
> predicate; use integers if you want to count things.

"Do that because that's what you're supposed to do, even if it makes
no difference" is another approach that's totally alien to my style of
teaching.  It's not rare in the evolution of a system for an assumed
"boolean" to become a count -- "do I have a printer or not?" becomes
"how many printers do I have?", a set (each item being or not being in
the set) becomes a bag (each item being in the bag 0, 1, ... N times),
and so on.  Fortunately, these issues are not as sharp in Python as they
would be in languages that can publish type-rigid interfaces, at least
as long as booleans remain confusable-enough with integers.  The best
case, of course, would be _total_ confusability... no separate boolean
type at all, just like today.  But given the high 'confusability' of the PEP
proposed booleans, the cost, or damage, is basically conceptual, more
than pragmatical -- "introducing a distinction without a difference" being
almost as naughty as "filling a badly-needed gap":-).


>> The "by convention" status of the canonical spelling for untrue
>> still holds, except that you want to change the convention to the
>> new object which exists solely for the value of changing that
>> canonical spelling, more or less.
> 
> No. If the goal had been to change the canonical spelling, two new
> builtins would have been sufficient. The goal was to create a new type
> for those, in addition to the new spelling.

Introducing two builtins would have a subset of the claimed benefits 
(attempt to standardize spelling to other than 0/1, but only in source,
not in program output) and a subset of the costs I see (e.g. the
"==True" issue would probably arise even then).  But note that the
new type was probably the simplest way to affect spelling in output
(by defining __str__ or __repr__), and the major issues are all
connected with spelling (in source and/or output).  Spelling apart,
you _could_ have an almost-transparent subtype of int and only
have very few issues indeed (breaking on type()==type() horrors
that probably do deserve to break, pickle roundtrip) -- maybe even
to the level that newbies _might_ be left ignorant of the change.
(I'd still rather not have that almost-transparent subclass of int, but
it would be such a minor issue -- almost invisible to most users,
blissfully -- that I'd probably not bother posting about it, I think).

Naah, "the spelling's the thing" -- in both output and source (two
issues which are connected by desiring eval(repr(x))==x).


>> 'if x == y:' should cause no warning, of course -- it's a general,
>> perfectly
>> good polymorphic usage.  Why should the user have to silence warnings
>> or break the smoothness of polymorphism to ensure against x, or y, or
>> both being of this newfangled bool type?
> 
> Indeed. I wonder how often the warning would trigger, though. I'd
> expect that people very rarely compare the result the got from a
> predicate to something else.

Indeed, I've seen people code "(x&&y) || ((!x)&&(!y))" (including the
overflow of parentheses) in cases where each of x and y were known
to be surely true or false, so the much-smoother "x==y" would have
sufficed -- they just hadn't _thought_ of that... some sort of
psychological block, I guess.  Still, that's no reason to penalize
those programmers who _are_ more facile with choosing simple
and smooth expressions for their logical needs.


>> > More realistically, the *parser* should emit a warning if it sees the
>> > name True used in such a context.
>> 
>> ...assuming the parser can determine at parse time that True stands
>> for the built-in value at that point -- or do you want to give True an
>> exhalted semi-keyword status, beyond that of, say, None, a dignity that
>> will produce frequent warnings if you rebind that identifier e.g. in a
>> local namespace?
> 
> I would indeed have the warning produced for all occurrences of True -
> perhaps a different warning if the parser can tell that True is bound
> at module scope. This is essentially what pychecker does in many
> similar cases, and Guido is in favour of moving some of the PyChecker
> warnings into the interpreter.
> 
> There would be an option to turn off parser warnings, of course.

OK.  On reflection, the 'slippery slope' of adding lint-like functionality
to the interpreter is one on which I probably won't mind sliding down -- as
long as there isn't only 'one' option (e.g. on the command-line) but also
a reasonably easy way for the user who knows what he or she is doing
to assert that to the checker (the warnings module seems a bit clunky
for that, but maybe I just haven't understood it well enough yet) for a
specific statement.


>> I know 'slippery slope' arguments are disliked around here, but both
>> this exchange and the various voices raised in clamor towards
>> 'stronger, purer booleans' suggest to me that PEP 285's own slope
>> may be slippery indeed.
> 
> These are different issues, though: those voices want to ban
> interactions between booleans and numbers; I want to ban binding of
> names that are also builtins (starting with None, True, and False).

Not just bindings -- also comparisons, you said.  A warning when any
builtin name is rebound (except when specifically turned off) sounds
good -- no reason to start from None, True, and False, when the
built-in names most often accidentally rebound are probably open (from
an errant 'from os import *' and the like), and type names (it's _so_ 
tempting to name an integer 'int', a list 'list', a dictionary 'dict', etc).
Warnings on comparisons and/or other operations involving booleans
are on the slope with very different slant that leads to just where I'd
_detest_ to see Python go;-).


>> No, but it's one more warning-case you have to propose (and how else
>> will one check for the wonderful new objects' identities if 'is True'
>> warns?! by twists and turns of isinstance checking for bool then int()
>> and == checking for 1...?!).  And 'is True' is very newbie-alluring: a
>> true 'attractive nuisance' (in more than one meaning of the phrase).
> 
> Ok, so the problem is more involved. I would suggest to produce the
> warning for 'is True', but not for 'True is' ... (I'm not sure whether
> I mean this seriously :-)

Given today's date, I wouldn't know.  I did use to campaign (not to much
use) for '0==x' in C (to avoid the typical bug of dropping an '=' from the
more usual 'x==0'), so playing around with operators that _are_
commutative but more error-prone depending on operand order is
hardly an entirely new concept:-).


>> > That's a good point: booleans should round-trip when pickling. I guess
>> > it is a bug in the PEP that this hasn't been spelled out.
>> 
>> If they do round-trip, then, it seems to me, we get a 'gratuitous'
>> incompatibility of pickles produced by 2.3 wrt 2.2 programs trying to
>> read them -- one more annoyance (and not a very attractive one either,
>> this time)
> 
> I'm not sure how big this problem is: it should be easy to add
> bool-loading function to Python installations for use with Python
> before 2.3. Packages that need to support cross-version pickling could
> incorporate such a feature.

Probably 'should', at least -- yet more work ('transitional', to be sure),
and so yet another cost of the PEP's adoption.  I don't consider it to
be necessarily all that 'easy' to encode metadata for all objects to
indicate which fields have switched to booleans, by the way -- quite
possible, sure, but 'easy' may be an overbid.  At the very least, it
seems to me that qualifying it as an 'annoyance' is hardly overdoing it.


>> And of course old pickles will give 0 and 1 so that much work will
>> be needed to reconstruct them into False and True when appropriate
>> *IF* it matters at all if something is True or 1.
> 
> This is a transitional issue. It may matter, but it may not matter
> enough to take action - depending on the application. An application
> that worries about cross-versioning pickling (presumable across
> versions of its own software as well) will have to take efforts
> already; avoiding to dump booleans will be a minor complication only.

An annoyance -- another little nugget on the 'costs' plate of the
scales, to add to the others.


>> So _why_ pay the price -- not a huge, world-racking one, but still
>> one nevertheless?
> 
> I could repeat the rationale of the PEP here, but I guess the question
> was rhetoric.

No, but neither would it be appropriate to repeat arguments against many
of which I've been arguing (either to point out why a claimed benefit would
not be one, or to indicate it would be truly minimal); rather, a summary of
what true, concrete benefits are left to offset against the costs might be
appropriate.  But as clearly we don't agree on most of what we've been
discussing on this thread, it may be that such a summary would serve no
real purpose.


Alex




More information about the Python-list mailing list