[comp.std.c++] Boolean confusion

dag@control.lth.se (Dag Bruck) (05/30/91)

In article <1991May29.171209.14760@neon.Stanford.EDU> philip@pescadero.stanford.edu writes:
>.... But how many programs would break? I for one would be prepared
>to pay the price for the long-term gain, but I generally try to program
>as if boolean and int are distinct types, so the price wouldn't be
>very high for me.

The "break old code" argument against any changes is the one you hear
most often at the C++ standardization meetings.  It is of course
valid, but often over-used.  Even if there were incompatible changes,
every compiler would have a switch to get the old behaviour.

One of the strongest arguments in favour of a new boolean data type is
that you could do function overloading:

	void f(int);
	void f(boolean);

I also think a boolean data type would increase type safety in C++, at
least the way I program (:-).

I once tried to implement `class boolean' and failed.  Firstly there
was a performance problem, which I think good compilers could
overcome.  Secondly, I don't think I gained anything in type safety
and little in convenience: to be at all useful I needed implicit type
conversions int->boolean and boolean->int.  I think a boolean data
type should _not_ be another kind of integer (at least eventually) which
can be implicitly converted to/from int.  It should instead be a
unique enumerated type, but that doesn't work until all standard
functions (e.g., operator == (int, int)) return a boolean and not
an int.

The transition to a better world (:-) should be done in two phases:

	1.  Introduce the new built-in data type `boolean' (or
	whatever you call it), and specify that all standard
	operator == (etc.) return a boolean.

	2.  Include implicit type conversions between boolean and
	int, to minimize the number of broken programs.  I think
	this automatic conversion will help in most cases.

	3.  Warn about the automatic conversions and label them as
	anachronisms.

	4.  (Some years later) Turn the warnings of (3) into errors.

We had a similar case with C++ 2.0 with respect to handling of `enum',
and I think the transition was relatively painless.  The most common
problem was that people had used an enum for booleans, which caused
warning messages under the new interpretation.

Dag Br!"uck
--
Department of Automatic Control		E-mail: dag@control.lth.se
Lund Institute of Technology
P. O. Box 118				Phone:	+46 46-104287
S-221 00 Lund, SWEDEN			Fax:    +46 46-138118

pena@brainware.fi (Olli-Matti Penttinen) (05/30/91)

In article <1991May30.060200.6590@lth.se> dag@control.lth.se (Dag Bruck) writes:

	   void f(int);
	   void f(boolean);

   I also think a boolean data type would increase type safety in C++, at
   least the way I program (:-).

   I once tried to implement `class boolean' and failed.  Firstly there
   was a performance problem, which I think good compilers could
   overcome.  Secondly, I don't think I gained anything in type safety
   and little in convenience: to be at all useful I needed implicit type
   conversions int->boolean and boolean->int.  I think a boolean data
   type should _not_ be another kind of integer (at least eventually) which
   can be implicitly converted to/from int.  It should instead be a
   unique enumerated type, but that doesn't work until all standard
   functions (e.g., operator == (int, int)) return a boolean and not
   an int.

I partly agree. It would be nice, if operator==(T,T) would return a
truly boolean value. On the other hand, it is possible to achieve the
same type safety if one implements not only a class boolean, but
classes real, integer, string, and what not, as well. That would of
course introduce a rather severe performance penalty, however. If only
current compilers did a better job in optimizing common
sub-expressions involving inlined access member functions and such... :-(

I know of at least one project, in which the group (they used Ada)
redefined practically everything, and to some extent succeeded. They
did peculiar things like had an "enum boolean { true, false, i_dont_care,
i_dont_know}" type of a construct.

Summa summarum: once again we face a consept that could be
incorporated to the language and indeed would fit in well, but without
which we can manage. IMHO, that means we shouldn't have it.
Especially, since no current library can support it.

   Dag Br!"uck
   --
   Department of Automatic Control		E-mail: dag@control.lth.se
   Lund Institute of Technology
   P. O. Box 118				Phone:	+46 46-104287
   S-221 00 Lund, SWEDEN			Fax:    +46 46-138118


==pena
--
Olli-Matti Penttinen <pena@brainware.fi> | "When in doubt, use brute force."
Brainware Oy                             |    --Ken Thompson
P.O.Box 330                              +----------------------------------
02151  ESPOO, Finland       Tel. +358 0 4354 2565       Fax. +358 0 461 617

tom@elan.Elan.COM (Thomas Smith) (05/31/91)

[ Continuing thread about merits/pitfalls of defining a boolean type
  in your application, and colliding with definitions in other modules. ]

From article <1991May30.060200.6590@lth.se>, by dag@control.lth.se (Dag Bruck):
> I once tried to implement `class boolean' and failed.  Firstly there
> was a performance problem, which I think good compilers could
> overcome.  Secondly, I don't think I gained anything in type safety
> and little in convenience: to be at all useful I needed implicit type
> conversions int->boolean and boolean->int.

I have successfully implemented Boolean data types in several large
projects (100K+ lines of C++) at the last two companies I have worked
for.  If you set it up right, you do get the type-safety without the
performance penalty.  In most cases, the biggest concern was size -
could we get a Boolean class that would have size == 1 byte (the minimum)
and align on single-byte boundaries when packed in structures.  The
answer is... depends on the architecture.  Here is what I usually end
up with:

    class Boolean {
	unsigned char value;

	friend int operator== (Boolean left, Boolean right);
	friend int operator!= (Boolean left, Boolean right);
    public:
	Boolean()  {}
	Boolean(int i) { value = ((i) ? 1 : 0); }

	operator int() const { return (int) value; }
    };

    inline int operator== (Boolean left, Boolean right)
		    { return left.value == right.value; }
    inline int operator!= (Boolean left, Boolean right)
		    { return left.value != right.value; }

    // defined in the source file as initialized to 0 and 1, respectively
    extern const Boolean FALSE;
    extern const Boolean TRUE;

Notice that initialization by int is allowed (via constructor),
but assignment is not (no operator=(int)).  There are some pitfalls
with this approach, however:
  1) The type name Boolean sometimes collides with "helpful" libraries
     that *just know* you will need a type called Boolean that is a
     typedef'd unsigned char.  The X toolkit (Xt) is a prime offender.
     Folks, what's the point of sticking the Xt prefix on 95% of the
     types defined, and skipping the 5% most likely to collide with
     an application's own types?

     This can be worked around by simply calling your Boolean something
     else, like TBoolean (Tom's Boolean :^), and undefining TRUE and FALSE
     at the beginning of the header file (if they were defines and not an
     enum).
  2) The constant values TRUE and FALSE are globals that are initialized
     via constructor, and thus cannot be safely used in other global
     constructors.  Buckle up for safety...

All in all, though, the good outweighs the bad.  One other reason that I
usually settle on the class approach for Boolean types is that I often
need many other similar types - for instance Status (SUCCESS or FAILURE) -
which are not compatible with Boolean and can cause trouble if they
are assigned to each other.  (Of course, Status is defined as int by
the X11 Xlib.h header file - don't get me started on graduate-student
software again).

Hope this was somewhat helpful - I feel better now.
    Thomas Smith
    Elan Computer Group, Inc.
    (415) 964-2200
    tom@elan.com, ...!{ames, uunet, hplabs}!elan!tom

npw@eleazar.dartmouth.edu (Nicholas Wilt) (06/02/91)

Defining your own Boolean type (with #defines, typedefs, or classes, as you
prefer) has advantages, but they are far outweighed by the problems
introduced when someone tries to use your code (or, conversely, when you're
trying to deal with code full of Booleans of one flavor or another).
What happens when you try to make use of two libraries, one of which thinks
Boolean is a "typedef int" and another which thinks Boolean is a class?
You could go through renaming and reworking, but that shouldn't be
necessary.

C++ inherits a pretty reasonable treatment of integers as Boolean values 
from C (nonzero is True when evaluating, Boolean expressions evaluate to 
integer 1 or 0).  It's portable, reasonably clean and flexible--for
instance, there's no other way to stuff multiple Booleans into a single 
word, like you can with the : construct in C structures.  A little less
pretty than any of the ten thousand other ways people can think of to
deal with Boolean values, but unlike any of those, it's standard.

Overall, I think the disadvantages outweigh the advantages.  I hate
buying C source code and seeing Boolean defined explicitly.  It gets 
ripped out as soon as a need develops to interface with it more than 
perfunctorily.

--Nick
  npw@eleazar.dartmouth.edu