[Python-bugs-list] [ python-Bugs-795791 ] bool() violates a numeric invariant

SourceForge.net noreply at sourceforge.net
Wed Aug 27 08:05:31 EDT 2003

Bugs item #795791, was opened at 2003-08-27 03:56
Message generated for change (Comment added) made by dtorp
You can respond by visiting: 

Category: Python Interpreter Core
Group: Python 2.3
Status: Open
Resolution: None
Priority: 5
Submitted By: David Albert Torpey (dtorp)
Assigned to: Nobody/Anonymous (nobody)
Summary: bool() violates a numeric invariant

Initial Comment:
The Liskov Substitution Principle states:   If for each 
object o1 of type S there is an object o2 of type T such 
that for all programs P defined in terms of T, the 
behavior of P is unchanged when o1 is substituted for o2
then S is a subtype of T.

The current implementation of bool() violates this rule 
by breaking an invariant for its parent, int() and its 
related numeric types, float(), complex(), and long():

>>> for typ in (int, long, complex, float, bool):
...     print typ(0), typ(str(typ(0)))

0 0
0 0
0j 0j
0.0 0.0
False True

In theory, polymorphism requires that a subclass object 
be substitutable into any code that would accept an 
instance of a parent class.  Here, the False instance is 
clearly not substitutable for zero in serializer code.

This is not just a theoretical problem, it arises in 
practice and caused problems for a comp.lang.python 
participant who was writing an XML serializer that 
depended on numeric types being able to reconstruct 
themselves from their string representations.

Another poster pointed out that the programmer could 
have used eval(repr(typ(0))), but that is not 
satisfactory because it is unsafe to run eval() on 
serialized data from an external source.

One possible fix is to make a special case so that bool
("False") returns False.  While this is a bit strange in 
that all other non-empty strings evaluate to True, it has 
the advantage of producing the expected behavior and 
only being damaging to the highly unlikely and 
probably erroneous case where someone relied on bool
("False") evaluating to True.

A more conservative fix is to issue a warning whenever 
encountering bool("False").  The will at least keep a 
probable error from passing silently into the good night.


>Comment By: David Albert Torpey (dtorp)
Date: 2003-08-27 14:05

Logged In: YES 

While quite funny, the comments are unhelpful.  There is a 
pickle protocol but not for bool. The original post also pointed 
out that bool('False')==False would break code; however, 
bool() is brand new in Py2.3 and the *only* code affected 
would be in the extremely improbable case of someone 
expecting that bool('False')==True.  It is a nit of strict 
reading that the LSP was originally stated as an inverted 
if/then because it was being presented in the context of 
mathematical proofs -- the correct reading in the current 
context is that child instances *must* be fully substitutable 
for parent instances.

Leaving bool() as it stands breaks an important invariant for 
int, long, float, and complex.  There is a reason that all of 
these have a provision for being able to coerce their str() 
forms back into the original -- that is a key feature and its 
application is not limited to pickling.  The PEP clearly states 
that bools should behave like ints -- for instance, it is 
intentional that True + 3 == 4.

If integer addition worked in every case except fo 5+6, would 
you fix the C code for integer additional or would you have 
every user of addition insert a "simple if" to create a custom 
work-around?  Don't answer, it is a rhetorical question.

I realize that there is no clean solution as there is a tension 
between the expected invariant and the usual meaning of all 
non-empty strings as True.  The correct balance comes from 
looking at the use cases and asking what is the 
programmer's expected outcome when they type:  bool
("False").  IMHO, the answer falls 99% towards False and 1% 
towards "True".


Comment By: Christos Georgiou (tzot)
Date: 2003-08-27 11:29

Logged In: YES 

There is the pickle protocol with its __getstate__, 
__setstate__ methods, which seems more appropriate than str
() and eval(); however, these methods are not defined in the 
base types for XML serialisation.

Changing bool('False') to evaluate as False instead of True for 
all Python programs would introduce breakage; why do that 
instead of a simple special-cased 'if' in a program that does 
XML serialisation?

BTW I don't see any violation of the Liskov Substitution 
Principle; as stated, it works one way (ie in this case it fails, 
so based on the principle you *cannot* prove that bool is a 
subtype of int, but we know that bool *is* a subtype of int --
it's in the source).  The LSP is a method to understand if S is 
a subtype of T, not a necessary step for the definition of S.

And a little tongue in cheek: the Christos Similarity Principle.  
If for each person P there is another person B who has an 
astonishing similarity in appearance, has almost exactly the 
same age and was born in the same location as person P, 
then person B is a sibling of person P.  Does that mean that 
my brother is not my sibling just because he doesn't look like 
me, is 14 years younger and wasn't born in the same hospital 
as me? :)


You can respond by visiting: 

More information about the Python-bugs-list mailing list