PEP 285: Adding a bool type

Ken Seehof kseehof at neuralintegrator.com
Sat Apr 6 15:32:13 EST 2002


 
> Still haven't found the time to read my original post, notice that
> I _did_ correct the name in the original post, and understand what
> I was trying to say, I see.  I will correct your misconception
> because you might confuse somebody else.
> 
> I am objecting to the fact that isleap, whatever the hell it is
> called, returns a boolean.  I am rejecting the existence of
> booleans in the language because it is too hard to teach how
> to use them properly.  Most people never learn.  Most code that
> uses booleans should not.

I agree with you, but I would say that the name isleap() should not
exist.  The problem is not with booleans, but with poor function
naming.  I'd prefer leapdays(year) that returns int.  If someones
makes the mistake of writing a function named isleap, they should
keep there promise implicit in the name and always return boolean.
The name is very much to the point.

> Proper use of booleans requires not only that you have a 
> function that returns one of two values, but THAT YOU NEVER
> EVER WANT THAT FUNCTION TO EVER BE MODIFIED TO RETURN ONE OF THREE,
> (or more).  What I tell my students is that you really want 
> a hole to open in the ceiling and a Warner Brothers safe to fall
> on the head of somebody who attempts to extend, subclass, or 
> in any other way change the function to return one of three values.

Proper use of booleans requires that the function evaluates
whether or not a proposition is true.  It is not sufficient that
the fuction merely returns two values.

Even if you are returning int, the safe will fall if the name of the
function implies a 0 or 1.  For example:

  if isleap(year):
      y = y+1

The above code is quite reasonable given the name of the function.
However, it will break if isleap returns a 2.  This is the fault
of the person who wrote the function, and especially the fault of
the person who foolishly extends the function to return a 2 without
renaming the function and going through all of the code that uses
the function.  If isleap is in an API, there is no good solution!

  if leapdays(year):
      y = y+1

This code has the same effect, but now the blame is on the person
who wrote the above code, not the person who wrote or modified the
function.  The difference is in the name (and perhaps the docs).
It is clear from the name of the function that the proper code
should be:

  y = y+leapdays(year)

On the other hand, the following code is ugly no matter what type
is returned:

  y = y+isleap(year)

But this looks ok to me:

  y = y+int(isleap(year))

> And, by God, if the function that returns _the number of leap days
> in the year_ isn't safe, at 0 or 1, then damn near close to nothing
> that my students are going to be tempted to use 'True' and 'False'
> for is.  This example makes my course notes, under Why using booleans 
> is bad, and you should never do it.  (unless you are a mathematician
> who wants to do real 2-valued algebra, or somebody interfacing with
> some other piece of software that needs those sort of bools, or 
> some other, EXTREMELY RARE,  person.  Don't you guys interrupt here.
> This is hard enough to teach as it is.)

How about a section "When not to use booleans"?

A function leapdays(year) that returns the number of leap days in the
year should return an integer.

A function isleap(year) that specifies whether or not the year is
a leap year should return a bool.  (better not to write this anyway)

I would tend to prefer to implement the former.  If someone foolishly
implements a boolean isleap function and the world government in
2024 decides to declare a double-leap year for political reasons, at
least you will -know- that you have to double check all of the code
that uses your function, since your self-documenting code implies a
promise that isleap will never return 2 or -1.  I would call it a bug
and fix it by renaming the function to leapdays returning integer,
then go through every usage of isleap and replace it with leapdays
while making sure that the code handles values other than 0 and 1
correctly.  Note that I would do have to go through this procedure
whether or not python has booleans.

Even without booleans in the language it would be inappropriate to
name a function isleap if there is some possibility that the value
will ever not be 0 or 1 since the name implies a promise never to make
such a change.  Booleans merely make such promises explicit.

By distinguishing between bools and ints, you motivate your students
to learn to write functions like leapdays(year) rather than
isleap(year).

> It does not help that it appears to the outside that Guido just went
> through all the python functions that returned 1 or 0 and changed
> them to return True or False.  I know that Guido would not be
> so stupid, and that there is a reason why he wants, for instance,
> isinstance to return only 0 or 1 for evermore, but I can't see it.
> I would like an isinstance that returned 0 for not an instance of
> this class, 1 for a direct instance, and 2 for a subclass.  There
> must be a lot of code out there I have never seen that relies on
> this never happening, and now, alas, I have to find out why.

I think that changing any function that used to return 0 or 1 to
return other values is likely to break code.  The desire for that
kind of flexibility is a seriously perverse interpretation of
polymorphism.

> Because my students will ask, of course.  If True and False are
> good enough for Guido, then it's good enough for them.  I would
> love it if a huge comment was added to python files that now
> return booleans saying why it was necessary to restrict the
> return values to one of 2 forever more, so people are not confused
> into thinking that returning booleans is a good idea in general,
> but that may be too much to ask for.  I would add the comments
> myself, but I am having problems seeing what the reasons are.
> Maybe after I get some more sleep, it will come clearer to me.

Any case that requires such documentation should not return bool.

I can think of several that don't need such documentation:
__eq__, __gt__, ...
hasattr
is_foo

> I truly liked telling students, especailly ones that have never used
> Python while we are using some other language,   'You don't need 
> True and False. Look at Python.'  
> 
> Now I have to say, to the students who are using
> Python: 'Python has True and False.  It is not for you little
>          worms, and if I catch you using it I will make you do 
>          the assignment over.'
> 
> I know in all the Python code I have ever written I have only 5 times
> wanted a boolean True or False -- all times when I was talking to a
> database that required it.  The rest of the time I wanted an integer,
> 0 or 1.  Even if I couldn't see a way that somebody was likely to
> extend it to return 3, there most certainly was never ever going to be
> any code that required that it only have one of 2 values, so now I
> will have to change all my True and False there to be 'Yes' or 'No' or
> something.  (grumble, now I wish I had lost the argument to the person
> who wanted the constants we picked to be TRUE and FALSE).

Why?  True and False will still behave like 1 and 0 if my understanding
of the PEP is correct.

Also, I don't believe you about only using booleans 5 times.  Every
time you use an 'if' statement you are using a boolean concept and
your code follows exactly two paths.  Every time you use >, =, < you
are using boolean concepts with corresponding expectation of two
possible results.  You probably mean that you only created variables
or functions with boolean values on five occaisions.  That is quite
reasonable.  Boolean varables and high level boolean functions are not
as common as boolean library functions and certain kinds of methods.
 
> Teaching people to not use booleans is hard.  They grab for them
> whenever they have a function that returns one of two values.  It
> was a lot easier to teach this concept when the fool things were not
> in the language.

Okay, you may have a point there.  However, IMO time spent gaining 
a clear concept of booleans is time very well spent.  In fact you
have come up with several excellent examples of when not to use
booleans.  You should add them to your lesson plan.  Every time you
see a student innappropriately returning bool to represent a pair
of values, you have an excellent opportunity to teach them to think
clearly about types in general.  I believe this lesson is so general
that it could help avert the Y2Ks of the future.

> Note:  don't tell me that because python bools are just ints, it
>        doesn't matter -- people who were using bools for
>        DEMOCRAT and REPUBLICAN can now add 
>        THE_DAMN_VOTE_WASNT_PUNCHED_THROUGH - (the integer 3)
>        when to their horror they discover 2 values was not enough.
>        I need to teach students to not use bools in languages which
>        are not so forgiving.
> 
> Laura Creighton

Perfect!  Bool should not be used to represent DEMOCRAT and
REPUBLICAN because party is not a boolean concept even if you
believe that there are only two parties!  Booleans are meant to
represent things that are true or not true.  Any value that I would
even be tempted to use a boolean for would certainly not be extended
to an integer.  Perhaps a float would be more likely, if I wanted
to used fuzzy logic :-)  Hmm.  Fuzzy logic.  Hmm.  Maybe the 'if'
statement should be extended to use fuzzy bools and automatically
fork weighted threads...  But I digress.  My point is that boolean
values are conceptually distinct from integers, even the set {0,1}.

- Ken Seehof







More information about the Python-list mailing list