Previous section   Next section

Imperfect C++ Practical Solutions for Real-Life Programming
By Matthew Wilson
Table of Contents
Chapter 15.  Values


15.3. Bending the Truth

Boolean logic is based on the notion of two states, 0 and 1. Correspondingly, the C++ bool type is similarly defined (C++-98: 3.9.1.6) to hold values of true or false. What could be simpler, or better? Those of us that had to program C++ before bool was introduced certainly yearned for such a type, and many Boolean pseudotypes have been created. They've been based on enums, constants, and #defines, but none had all the features and support that a fully fledged type would provide, hence bool was introduced in C++-98.

Alas, even in the standard (C++-98: 3.9.1.6; note 42), it is noted that "using a bool value in a way described . . . as "undefined" . . . might cause it to behave as if it was neither TRue or false." This would never happen to you, right?

Well, it's very easy to synthesize an example:



reinterpret_cast<char&>(b) = 128;





if(b != false)


{


  printf("b != false\n"); // This is printed, ...


}


if(b != true)


{


  printf("b != true\n"); // as is this, ...


}


if(b)


{


  printf("b is implictly true\n"); // and this.


}



Of course, this is an artificial and deliberate sabotage of the type system, from which good programming practice will protect you 99 percent of the time, but there are still times when it can "byte" you. Commonly this is when using unions, and when interacting with other languages, such as C, as we saw in section 13.4.2.

In The Gods Themselves, Isaac Asimov said there are no meaningful numbers other than 0, 1, and infinity [Asim1972].[6] The bool type purports to support two values, which violates this rule, and the practical effect is that it supports a theoretically infinite (albeit practically bounded by its bit-size representation) number of values.

[6] Mind you, I bet he never had a fuzzy-logic rice cooker.

Imperfection: Having more than one discrete value for the Boolean type is dangerous.


Three solutions are possible. First, the language could dictate, or compiler vendors could opt to assume, that any conditional statement involving the literal true be rewritten in the obverse using the literal false. In other words, the following expression:



if( i &&


    b1 == true &&


    ( j < 3 ||


      b2 != true))



would be interpreted as



if( i &&


    b1 != false &&


    ( j < 3 ||


      b2 == false))



Since neither language nor compilers do this at the moment—and probably never will—the second, practical, measure is for you to ensure that you never compare against the literal true in your code.

Third, we'll see in section 17.2 that there are good reasons to ensure that all conditional subexpressions are Boolean. Since bool types are, by definition, Boolean, it is appropriate to avoid comparison with the literals altogether, and use the variable itself to test for truth, and its logical negation to test for falsehood, as in:



if( i &&


    b1 &&


    ( j < 3 ||


      !b2))



This is the accepted way of programming with Booleans, is undoubtedly more attractive, and most programmers do this without thinking about it. If that's not you, then maybe you should think about it: you can avoid the problems by simply getting rid of true (and, perhaps, false) from all conditional expressions in your own code.


      Previous section   Next section