[comp.lang.c++] Time to standardize "true" and "false"

nagle@well.UUCP (John Nagle) (09/22/89)

     I would like to suggest that the time has come to standardize the
Boolean values in C.  Most programs have definitions of these, but they
differ and clash.  As the typing rules become ever tighter, and the number
of commercial libraries available grows, this becomes a more and more
serious problem.  Commercially published libraries have spellings such
as "TRUE", "true", and "True", forms of definition including "#define",
"const", and "enum", and Boolean types (spelled variously) defined
as "char", "unsigned char", "unsigned short", and "enum".

     This has got to stop.

     I would suggest that the standardized definition be

	const boolean (false=0, true=1);

which follows the convention that predefined types in C are all lower
case.  The explicit values for "false" and "true" are given, although
redundant, to make the point that those values are part of the specification
and are not an accident of the ordering in the definition. 

     It should be mandated that this definition be a part of the C
and C++ header files, preferably in an ANSI-specified file.
"stddef.h" seems a likely choice, but this is open to discussion.

     If it's too late to fix this in C, it should be fixed in C++, where
typing is taken more seriously.

					John Nagle

blarson@basil.usc.edu (bob larson) (09/22/89)

In article <13730@well.UUCP> nagle@well.UUCP (John Nagle) writes:
>
>     I would like to suggest that the time has come to standardize the
>Boolean values in C.
[...]
>     I would suggest that the standardized definition be
>	const boolean (false=0, true=1);

Why don't we just change the languae so it has this stuff built in?
Perhaps we can find a way that dosn't add more keywords to the
language... the little-known keyword "int" should be able to do
double-duty as boolean, and the keywords 0 and 1 should work just fine
as false and true.  Let's see what other changes are needed to the
languge... none.  Gee, it seems that maybe this was one of the uses
theese keywords were designed for. :-)

-- 
Bob Larson	Arpa:	blarson@basil.usc.edu
Uucp: usc!basil!blarson

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/22/89)

In article <13730@well.UUCP> nagle@well.UUCP (John Nagle) writes:
>     I would suggest that the standardized definition be
>	const boolean (false=0, true=1);

I don't know what that is supposed to mean; it's not C.

>     It should be mandated that this definition be a part of the C
>and C++ header files, preferably in an ANSI-specified file.

The result of a nominally Boolean expression in C is well-defined;
it has int type with value 1 for true, 0 for false.

>"stddef.h" seems a likely choice, but this is open to discussion.

Not really.

There is no problem insofar as the C Standard goes; "bool", "true",
etc. are not reserved words and have no special meaning.  The
problem you describe comes about only when you #include headers
for several unrelated (or at least uncoordinated) libraries.
In such a case, this is merely a small part of a name-space clash
problem.  You should address the general problem instead of one
small aspect of it.

newsuser@lth.se (LTH network news server) (09/22/89)

In article <13730@well.UUCP> nagle@well.UUCP (John Nagle) writes:
>
>     I would like to suggest that the time has come to standardize the
>Boolean values in C.

I completely agree that a boolean data type is needed in C++.  I
think the definition should define the following properties:

	1.  The data type is called "boolean".
	2.  The allowed values are "false" and "true".
	3.  int(false) = 0 and int(true) = 1
	4.  boolean(0) = false, other values are true

I do not know if implicit conversion boolean <==> int should be allowed.

In the time before C++ 2.0, it was quite common to define a boolean type
as an enumeration:

	enum boolean {false, true};

Unfortunately (in this case), C++ no longer allows implicit conversion
int ==> enum, so the result of a comparison must be explicitly type cast:

	boolean b;
	b = (i == 3);		// warning
	b = boolean(i == 3);	// ok

This is rather clumsy.  We cannot define our own operator functions on
the boolean data type, because one of the arguments must be a class object.

	boolean operator == (boolean x, boolean y) {...}	// error

I do not understand exactly why this restriction is required, but apparently
it is.  Please enlighten me.

What remains is to define a class for boolean.  This is not easy to
make as efficient as the built in types, but the problem is mostly in
the lack of optimization in the code generators.  I have tried; you
will find my attempt to define a boolean below.  Note that I have not
defined the operators && and || -- I do not think we can achieve the
"short circuit" evaluation we're used to with a user-defined operator.

Dag Michael Bruck
--
Department of Automatic Control		Internet:  dag@control.lth.se
Lund Institute of Technology
P. O. Box 118				Phone:	+46 46-108779
S-221 00 Lund, SWEDEN			Fax:    +46 46-138118

==============================================================================

// Boolean data type

enum {false, true};

class Boolean {
public:
  Boolean()		{ val = false; }
  Boolean(int i)	{ val = (i != false); }
  Boolean(const Boolean& b)	{ val = b.val; }
  // Any non-zero value is true; default value is false.

  operator int()	{ return val; }
  // Type cast boolean => integer.

  void operator &= (const Boolean& b)	{ val &= b.val; }
  void operator |= (const Boolean& b)	{ val |= b.val; }
  void operator ^= (const Boolean& b)	{ val ^= b.val; }
  // Operator assignment.

  friend Boolean operator & (const Boolean&, const Boolean&);
  friend Boolean operator | (const Boolean&, const Boolean&);
  friend Boolean operator ^ (const Boolean&, const Boolean&);
  friend Boolean operator ! (const Boolean&);
  friend Boolean operator == (const Boolean&, const Boolean&);
  friend Boolean operator != (const Boolean&, const Boolean&);
  // These operators need access to the internal representation.

private:
  int	val;
  Boolean(long i) { val = int(i); }	// no check
};

inline Boolean operator & (const Boolean& p, const Boolean& q)
{ return long(p.val & q.val); }

inline Boolean operator | (const Boolean& p, const Boolean& q)
{ return long(p.val | q.val); }

inline Boolean operator ^ (const Boolean& p, const Boolean& q)
{ return long(p.val ^ q.val); }

inline Boolean operator ! (const Boolean& p)
{ return long(!p.val); }

inline Boolean operator == (const Boolean& p, const Boolean& q)
{ return long(p.val == q.val); }

inline Boolean operator != (const Boolean& p, const Boolean& q)
{ return long(p.val != q.val); }

// Note: there are no && and || operators.


Boolean f(Boolean b)
{
  return !b;
}


main()
{
  Boolean p, q, r;

  r &= p;
  r = p & q;
  r = f(p);
}
-- 
Department of Automatic Control		Internet:  dag@control.lth.se
Lund Institute of Technology
P. O. Box 118				Phone:	+46 46-108779
S-221 00 Lund, SWEDEN			Fax:    +46 46-138118

dog@cbnewsl.ATT.COM (edward.n.schiebel) (09/22/89)

From article <13730@well.UUCP>, by nagle@well.UUCP (John Nagle):

>      I would like to suggest that the time has come to standardize the
> Boolean values in C.  
HERE HERE!!!

	-Ed Schiebel.
	

nagle@well.UUCP (John Nagle) (09/23/89)

Correction: the definition should have read:
>	enum boolean (false=0, true=1);
     
       Doug Gwin at BRL points out that namespace clashes are a more
general problem in C.  But this isn't a namespace-control problem.
It's not that we want every package to have its own definition of
"boolean", all kept straight in some way and with conversion functions
between package A's "boolean" and package B's "boolean" somehow provided.

       "boolean" really ought to be part of the language, and the logical
operators should return results of type "boolean", but it's too late in
the history of C/C++ for that.  Nevertheless, we should at least have
a consistent definition within the current language structure.

					John Nagle

henry@utzoo.uucp (Henry Spencer) (09/23/89)

In article <13730@well.UUCP> nagle@well.UUCP (John Nagle) writes:
>     I would like to suggest that the time has come to standardize the
>Boolean values in C...

They are already standard.  Integer nonzero means true.  Integer zero
means false.  There is not the slightest hope of changing this now.
Furthermore, it's not clear that it's worth the trouble.
-- 
"Where is D.D. Harriman now,   |     Henry Spencer at U of Toronto Zoology
when we really *need* him?"    | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

ian@mva.cs.liv.ac.uk (09/24/89)

In article <1989Sep22.073138.19684@lth.se>, newsuser@lth.se (LTH network news server) writes:
> I completely agree that a boolean data type is needed in C++.  I
> think the definition should define the following properties:
> 
> 	1.  The data type is called "boolean".
>
That's just what _you_ want to call it! Why not call it `bool' or
`logical' or even `int'?

> 	2.  The allowed values are "false" and "true".
>
Why not call them `f' and `t' or `F' and `T' or even `0' and `1'?

> 	3.  int(false) = 0 and int(true) = 1
>
Well, int (0) = 0 and int (1) = 1.

> 	4.  boolean(0) = false, other values are true
>
Wouldn't it be great for conditionals in C to be false if they are testing
integer 0 and to be true if they are testing any other integer? That way
we could use integers instead of a new boolean type. Oh, looks like they
already do that!

Why do we need to introduce a new data type to do the job of a data type
we already have, but in a more complex way?

Ian Finch              Janet: ian@uk.ac.liv.cs.mva
---------              Internet: ian%mva.cs.liv.ac.uk@cunyvm.cuny.edu
                       UUCP: ...mcvax!ukc!ian@uk.ac.liv.cs.mva
===============================================================================
What's a word processor? Well, you know what a food processor does to food ...

wjf@attctc.Dallas.TX.US (Jesse Furqueron) (09/25/89)

In article <13730@well.UUCP>, nagle@well.UUCP (John Nagle) writes:
> 
>      I would like to suggest that the time has come to standardize the
> Boolean values in C.  Most programs have definitions of these, but they
> differ and clash.  As the typing rules become ever tighter, and the number
	
			xyzzy!! and text disappears...

> 
>      I would suggest that the standardized definition be
>      If it's too late to fix this in C, it should be fixed in C++, where
> typing is taken more seriously.
> 
> 					John Nagle


I would suggest rather than FALSE = 0 and TRUE = 1, that the "real" definition
of TRUE is not FALSE (TRUE = not 0), i.e. TRUE = !0.  Therefore the following

#define FALSE	0
#define TRUE	!0 

or for c++ folks

const boolean (FALSE=0, TRUE=!0);

I believe (if this tired and aged memory serves me correctly) that somewhere
K&R refers to this being the evalutations used in if and while statements.


Jesse Furqueron
VISystems
11910 Greeneville Suite 300
LB 29
Dallas, Tx. 75243
(214) 907-8080

-------------------------------------------------------------------------------
As always, the opinions expressed by myself are not necessarily those of my
employer... maybe one of these days they'll learn to listen!!!
-------------------------------------------------------------------------------

dhesi@sun505.UUCP (Rahul Dhesi) (09/25/89)

(The referenced article had a follow-up header of "poster", which I
think is a nasty thing to have done.)

In article <9464@attctc.Dallas.TX.US> wjf@attctc.Dallas.TX.US (Jesse Furqueron)
writes:
>#define FALSE	0
>#define TRUE	!0 

I suggest that defensive programmers eschew these constants because the
temptation to say

     if (x == TRUE) ...

may overcome you some day and you will suffer, unless you can
universally guarantee that you didn't absent-mindedly do something like

     x = isdigit(c);


If, on the other hand, you are willing to either be careful to always
say
     x = (isdigit(c) != 0);

or if you alternatively define

     #define ISTRUE(x)	(x)
     #define ISFALSE(x)	(!(x))

and say

     if (ISTRUE(x)) ...
     if (ISFALSE(y)) ...

instead then the use of TRUE and FALSE is not so dangerous.

Best is just think binary and say:

     x = 0;		/* x is false */
     y = 1;		/* y is true */

and for testing use

     if (x)  ...	/* if x is true */
     if (!y) ...	/* if y is false */

If you really must define a macro, try:

     #define ONE   1
     #define ZERO  0

Now if you see

     if (x == ONE) ...

you immediately realize that this could fail to work.

The problem is that in C any nonzero value is considered to be
true when tested in a boolean context, so

     #define TRUE  1

is misleading.  In a richer language you could perhaps say:

     #define TRUE  [-inf..-1, 1..+inf]

Rahul Dhesi <dhesi%cirrusl@oliveb.ATC.olivetti.com>
UUCP:  oliveb!cirrusl!dhesi

akenning@pico.oz (Alan Kennington) (09/26/89)

In article <1989Sep22.073138.19684@lth.se> dag@Control.LTH.Se (Dag Bruck) writes:
>In article <13730@well.UUCP> nagle@well.UUCP (John Nagle) writes:
>>
>>     I would like to suggest that the time has come to standardize the
>>Boolean values in C.
>
>I completely agree that a boolean data type is needed in C++.  I
>think the definition should define the following properties:
[...]

If a boolean type is required, it can easily be provided in C++, with whichever
properties are desired. Some people like, for instance to have:

enum boolean { false, true, maybe };

There must be some way of deciding which types should be built-in and which
should be user-defined. Otherwise, everything would have to be put in, and
then people would complain that the implementation wasn't quite what they
wanted.

I think it would be better to discuss the _principles_ of which types become
built-in and which don't, rather than proposing particular types, e.g.
"string", "complex", which should be built-ins.

It seems to me that there is a very simple rule which fits C. That is that
a type should be built in if a wide range of common architectures explicitly
support it. Hence int, long, char, float, double, pointer-to-something,
are all natural built-in types, which have machine instructions to support them.
However, the single-bit boolean variable has rather few machines which support
it per se. Most machines do operations on the whole byte, word, or longword,
not just on one bit. These operations are indeed specifically referred to by
C operations: &, |, etc.

So I think that the time to add "boolean" to the built-in operators will
be when common architectures support single-bit data representations and
operations that are more efficient than the corresponding operations on
whole bytes, words or longwords.

If people want a boolean type, then the C++ classes are meant for precisely
that purpose. It is contrary to the C/C++ minimalist spirit to burden the
language with a non-machine-supported type.

I am right, am I not?
("I'm right, aren't I?" is criticisable English.)

Alan Kennington.

bright@Data-IO.COM (Walter Bright) (09/26/89)

In article <9464@attctc.Dallas.TX.US> wjf@attctc.Dallas.TX.US (Jesse Furqueron) writes:
<In article <13730@well.UUCP>, nagle@well.UUCP (John Nagle) writes:
<<      I would like to suggest that the time has come to standardize the
<< Boolean values in C.  Most programs have definitions of these, but they
<< differ and clash.
<I would suggest rather than FALSE = 0 and TRUE = 1, that the "real" definition
<of TRUE is not FALSE (TRUE = not 0), i.e. TRUE = !0.

What's the point? !0 == 1. Period. It is not going to change. !0 is not
more portable or more readable.

I used to extensively use:
	typedef int bool;
	#define TRUE 1
	#define FALSE 0
I eventually gave this up because:
1. Name space collisions with other people's code.
2. Frequent confusion of whether TRUE meant !=0 or if it really meant 1.
   Note that functions like isalpha() return !=0 or 0, not 1 or 0. This
   means that if you wish to precisely use TRUE/FALSE, you have to write code
   like
	condition = (isalpha(c) != 0);
   which is an efficiency problem.

Now, I simply use code like:

/****************************
 * Test for a condition.
 * Returns:
 *	0	condition not satisfied
 *	!=0	condition is satisfied
 */

int testcondition(args)
	...

P.S. One of my pet peeves is code like:
	#ifdef notdefined
instead of
	#if 0
For the former, I have to grep all the c, h and makefiles to make sure
notdefined is never defined. For the latter, there can be no problem.
Ditto for stuff like
	while (ALWAYS)
	loop_forever
instead of
	while (1)

karzes@mfci.UUCP (Tom Karzes) (09/26/89)

In article <9464@attctc.Dallas.TX.US> wjf@attctc.Dallas.TX.US (Jesse Furqueron) writes:
>I would suggest rather than FALSE = 0 and TRUE = 1, that the "real" definition
>of TRUE is not FALSE (TRUE = not 0), i.e. TRUE = !0.  Therefore the following
>
>#define FALSE	0
>#define TRUE	!0 

That's silly.  You should either assume the values that C guarantes:

    #define FALSE 0
    #define TRUE  1

Or else assume nothing and let the compiler figure it out each time:

    #define FALSE (0 != 0)
    #define TRUE  (0 == 0)

Your mistake is that you're confusing C's truth test (!= 0) with its
canonical true and false values (F=0, T=1).  In general, the canonical
true and false values in a language must behave appropriately under its
true test, but there may be non-canonical values which do the same.
In C, there is only one integral false value.  However, there are
also false pointer and floating point types.  In that sense, the "!= 0"
test in itself says nothing about canonical false being an integer zero.

Since they should only be defined once, I think it's a bit extreme to
use the latter definitions shown above, but they do provide the proper
justification for 0 and 1, which are best thought of as constant folded
versions of these (or similar constant expressions which generate canonical
true and false values without depending on what those values are).

karzes@mfci.UUCP (Tom Karzes) (09/26/89)

In article <895@cirrusl.UUCP> dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) writes:
>(The referenced article had a follow-up header of "poster", which I
>think is a nasty thing to have done.)

I agree.

>I suggest that defensive programmers eschew these constants because the
>temptation to say
>
>     if (x == TRUE) ...
>
>may overcome you some day and you will suffer...

I agree that this sort of thing does happen, particularly in a language
like C which doesn't support a distinct boolean data type but does support
boolean operations defined on integers.  However, I feel that it is primarily
a matter of understanding and engineering discipline.  Proper use of a user
defined boolean data type will only attempt to represent canonical true and
false values in that data type.  It should be sufficient to define:

    typedef int     bool;
    #define FALSE   0
    #define TRUE    1

and to then only use bool to hold TRUE or FALSE (which includes values
generated by comparisons, !, &&, ||, etc.).  Under this usage, the following
constructs should never appear for bool's b, b1, and b2:

        bad form                preferred equivalent
    ----------------            --------------------
    b == FALSE                      ! b
    b != FALSE                      b
    b == TRUE                       b
    b != TRUE                       ! b
    b ? TRUE : FALSE                b
    b ? FALSE : TRUE                ! b
    b1 ? FALSE : b2                 (! b1) && b2
    b1 ? TRUE : b2                  b1 || b2
    b1 ? b2 : FALSE                 b1 && b2
    b1 ? b2 : TRUE                  (! b1) || b2

Expressions of type bool should not be used as integer expression unless
explicitly case to type int, to indicate that the F=0, T=1 behavior is
being assumed.  The need for this shouldn't arise very often (only in
tight little pieces of code where you want to do something like optionally
add 1 to a number, depending on a bool value, and you want it to be really
tight code so you simply add the cast bool, as opposed to "b ? 1 : 0").

dld@F.GP.CS.CMU.EDU (David Detlefs) (09/26/89)

Several of the posts on this subject have been of the form "why bother
if you've already got the int type that does everything you want?"
I kind of agree, but I kind of don't: I think you would only really
gain something if you really went for it and made Bool (or whatever)
part of the language.  Specifically:

1) "If," "while," "for," and "do" statement tests would require a boolean.
2) Relational operators (==, >, &&, etc) would return a boolean.

I think this might result in measurably safer programs.  Just think,
errors of the form

   if (i = 0) ...

would become errors.  (I'm assuming that there is no implicit
conversion between int and boolean.)

If you don't take the full step (and I have no hope of this actually
happening; there are probably good reasons not to do this.  Like
backwards compatibility) then it's probably not worth doing.

Ah well.

Dave


--
Dave Detlefs			Any correlation between my employer's opinion
Carnegie-Mellon CS		and my own is statistical rather than causal,
dld@cs.cmu.edu			except in those cases where I have helped to
				form my employer's opinion.  (Null disclaimer.)

garys@bunker.UUCP (Gary M. Samuelson) (09/26/89)

In article <1885@mva.cs.liv.ac.uk> ian@mva.cs.liv.ac.uk writes:

>Wouldn't it be great for conditionals in C to be false if they are testing
>integer 0 and to be true if they are testing any other integer? That way
>we could use integers instead of a new boolean type. Oh, looks like they
>already do that!

In any argument, I find I will tend to take the side opposite that which
is supported largely by ridicule and sarcasm.

>Why do we need to introduce a new data type to do the job of a data type
>we already have, but in a more complex way?

It seems to me that your arguments (such as they are) would apply
equally to "short" and "long" (perhaps even "char").  Why do you think
I should use 32 bits ("int" in some environments) when 1 would do?
I favor the addition of "boolean" to "C" -- it's only logical.

Gary Samuelson

tneff@bfmny0.UU.NET (Tom Neff) (09/26/89)

There is so much code that already thinks it has to - and can - define
what "boolean" is, that adding a reserved "boolean" type would probably
be greeted with more groans than cheers.  Nor does much of this existing
code make any room for 1-bit implementations, from what I've seen.

I think that at MOST, "boolean," "TRUE" and "FALSE" should have the same
status as "NULL," i.e., some (new) standard header like <bool.h> should
define them if you bother to include it.  And the guidance would suggest
saying

	#define boolean int
	#define TRUE 1
	#define FALSE 0

although I have always smiled on clevernesses like

	#define TRUE (1==1)
	#define FALSE (1==0)

-- 
'The Nazis have no sense of humor, so why   -|  Tom Neff
should they want television?' -- Phil Dick  |-  tneff@bfmny0.UU.NET

fishkin@pixar.UUCP (Ken Fishkin) (09/26/89)

In article <2142@dataio.Data-IO.COM> bright@dataio.Data-IO.COM (Walter Bright) writes:
]In article <9464@attctc.Dallas.TX.US> wjf@attctc.Dallas.TX.US (Jesse Furqueron) writes:
]<I would suggest rather than FALSE = 0 and TRUE = 1, that the "real" definition
]<of TRUE is not FALSE (TRUE = not 0), i.e. TRUE = !0.
]
]What's the point? !0 == 1. Period. It is not going to change. !0 is not
]more portable or more readable.

    I disagree. I have worked in environments where !0 was -1.
Setting TRUE to !0 is indeed more portable.
    Furthermore, it better captures the fact that in 'if' tests,
the 'true' branch is taken on non-zero, not just on '1'.
-- 
Ken Fishkin	...ucbvax!pixar!fishkin

sartin@hplabsz.HPL.HP.COM (Rob Sartin) (09/27/89)

In article <DLD.89Sep25164955@F.GP.CS.CMU.EDU> dld@F.GP.CS.CMU.EDU (David Detlefs) writes:
>I think this might result in measurably safer programs.  Just think,
>errors of the form
>
>   if (i = 0) ...
>
>would become errors.  (I'm assuming that there is no implicit
>conversion between int and boolean.)

and all of the programs of the form:

  SomeType *Current;

  while (Current = Foo.Next()) {
    // Do something with Current
  }

would suddenly become illegal even though that is a common idiom for
traversing lists.

Rob Sartin			internet: sartin@hplabs.hp.com
Software Technology Lab 	uucp    : hplabs!sartin
Hewlett-Packard			voice	: (415) 857-7592

roemer@cs.vu.nl (Roemer Lievaart) (09/27/89)

blarson@basil.usc.edu (bob larson) writes:

>>     I would suggest that the standardized definition be
>>	const boolean (false=0, true=1);

	false=(0==1), true=(0==0)

ark@alice.UUCP (Andrew Koenig) (09/27/89)

The trouble at the root of all this discussion is that

	x == y

is defined in C as being an int.  This isn't going to change
any time soon, and making C++ differ from C in such a fundamental
respect seems unlikely to be capable of gaining as much as it
would cost.
-- 
				--Andrew Koenig
				  ark@europa.att.com

rhg@cpsolv.UUCP (Richard H. Gumpertz) (09/27/89)

The biggest advantage of a built-in boolean type would be that casts TO it
would test for zero/non-zero rather than just trucating the high-order bits
if sizeof(source) is bigger than sizeof(bool).  Also, (bool)X & (bool)Y would
do "right" thing even if X was 4 and Y was 32.  In other words, & would be
equivalent to && for type bool except that both operands would be evaluated.
-- 
==========================================================================
| Richard H. Gumpertz:                        ...uunet!amgraf!cpsolv!rhg |
| Computer Problem Solving, 8905 Mohwak Lane, Leawood, Kansas 66206-1749 |
==========================================================================

wen-king@cit-vax.Caltech.Edu (King Su) (09/27/89)

In article <7701@bunker.UUCP> garys@bunker.UUCP (Gary M. Samuelson) writes:
<In any argument, I find I will tend to take the side opposite that which
>is supported largely by ridicule and sarcasm.

You shouldn't go around exposing your weakness like that; you can be
manipulated into taking any side.  :-)

>>Why do we need to introduce a new data type to do the job of a data type
<>we already have, but in a more complex way?
>
<It seems to me that your arguments (such as they are) would apply
>equally to "short" and "long" (perhaps even "char").  Why do you think
<I should use 32 bits ("int" in some environments) when 1 would do?
>I favor the addition of "boolean" to "C" -- it's only logical.

It doesn't have to be 32 bits.  Besides, using 32 bits is perfectly OK
if it makes the program faster and if speed is what you are after.  If
space is more important, you can do with 1 bit if you use bit field.
We can do just fine with what we got, so the question is why is boolean
needed and why is it, as you say, logical (perhaps you forgot a smiley).
-- 
/*------------------------------------------------------------------------*\
| Wen-King Su  wen-king@vlsi.caltech.edu  Caltech Corp of Cosmic Engineers |
\*------------------------------------------------------------------------*/

wen-king@cit-vax.Caltech.Edu (King Su) (09/27/89)

In article <393@cpsolv.UUCP> rhg@cpsolv.uucp (Richard H. Gumpertz) writes:
>The biggest advantage of a built-in boolean type would be that casts TO it
<would test for zero/non-zero rather than just trucating the high-order bits
>if sizeof(source) is bigger than sizeof(bool).  Also, (bool)X & (bool)Y would
<do "right" thing even if X was 4 and Y was 32.  In other words, & would be
>equivalent to && for type bool except that both operands would be evaluated.

Why not just do:

#define bool(a) (!!(a))

Then just use bool(X) whenever you wanted to use (bool)X.

-- 
/*------------------------------------------------------------------------*\
| Wen-King Su  wen-king@vlsi.caltech.edu  Caltech Corp of Cosmic Engineers |
\*------------------------------------------------------------------------*/

nagle@well.UUCP (John Nagle) (09/27/89)

In article <6897@pixar.UUCP> fishkin@pixar.UUCP (Ken Fishkin) writes:
>    I disagree. I have worked in environments where !0 was -1.

      That's an incorrect implementation in both C and C++.
K&R reads (sec. 4.6): "The unary negation operator converts a non-zero
or true operand into 0 and a zero or false operand into 1."  Strostrup
reads (sec 7.2): "The result of the logical negation operator ! is 1 if
the valu of its operand is 0, 0 if the value of its operand is non-zero".


					John Nagle

peter@ficc.uu.net (Peter da Silva) (09/28/89)

Rather than add a boolean type, make bitfeilds more like first-class objects:

typedef int boolean:1;

boolean x;	/* allocates, say, 1 byte */

boolean y, z;	/* allocates a byte each, so you can take an addr */

{
	register boolean a,b,c;	/* Allocates 1 byte for all: no addr needed */
	struct foo { boolean bar, baz; }; /* sizeof(foo) == 1 */
...
-- 
Peter da Silva, *NIX support guy @ Ferranti International Controls Corporation.
Biz: peter@ficc.uu.net, +1 713 274 5180. Fun: peter@sugar.hackercorp.com. `-_-'
"That is not the Usenet tradition, but it's a solidly-entrenched            U
 delusion now." -- brian@ucsd.Edu (Brian Kantor)

bright@Data-IO.COM (Walter Bright) (09/28/89)

In article <6897@pixar.UUCP> fishkin@pixar.UUCP (Ken Fishkin) writes:
<In article <2142@dataio.Data-IO.COM> bright@dataio.Data-IO.COM (Walter Bright) writes:
<]!0 == 1. Period. It is not going to change. !0 is not
<]more portable or more readable.
<    I disagree. I have worked in environments where !0 was -1.
<Setting TRUE to !0 is indeed more portable.

What compiler is that? It is definitely broken. Did it also evaluate
(0==0) as -1? If the only one it got wrong was !0, then setting TRUE
to !0 would cause more problems (probably very obscure ones).

In general, warping your source code to account for a particularly bad
compiler that you may be forced to deal with should be done with #if's.
For instance, I've had to deal with a compiler that didn't implement
switch statements properly. This is not a reason to abandon using switches.
The workaround was to:
	#if __BRAND_X_C__
		if (v == 1)
			...
		else if (v == 2)
			...
	#else
		switch (v)
		{   case 1:
			...
		    case 2:
			...
		}
	#endif
And, of course, reporting the problems to the vendor to try to get them
fixed.

foessmei@lan.informatik.tu-muenchen.dbp.de (Reinhard Foessmeier) (09/28/89)

In article <12067@cit-vax.Caltech.Edu> wen-king@cit-vax.UUCP (Wen-King Su) writes:
>...
>It doesn't have to be 32 bits.  Besides, using 32 bits is perfectly OK
>if it makes the program faster and if speed is what you are after.  If
>space is more important, you can do with 1 bit if you use bit field.
>We can do just fine with what we got, so the question is why is boolean
>needed and why is it, as you say, logical (perhaps you forgot a smiley).
>-- 

^Ci tiu diskuto iris tute alian         This discussion has taken a road com-
vojon ol mi komence imagis.  ^Cu        pletely different from what I first
ne unu el la precipaj avanta^goj        imagined.  Wouldn't one of the main
de C-tipo `boolean' estus, ke ^gi       advantages of a `boolean' type in C
ebligus pli striktan kontrolon de       be the possibility for stricter type
tipoj (pli ol la ^sparo de kelkaj       checking (rather than saving a few
bitoj)?  Kompreneble, tiuj belaj        bits)?  Of course, such beloved con-
konstrua^joj "x<y<z<u" tiam ne          structs as "x<y<z<u" would no longer
estus eblaj, se ne permesi ankaw        be possible, unless comparison of
komparon de bule-oj.                    `boolean's would be permitted.

>/*------------------------------------------------------------------------*\
>| Wen-King Su  wen-king@vlsi.caltech.edu  Caltech Corp of Cosmic Engineers |
>\*------------------------------------------------------------------------*/
__________
Reinhard F\"ossmeier, Technische Univ. M\"unchen | UNOX is a trademark of
foessmeier@infovax.informatik.tu-muenchen.dbp.de |     "Union Deutsche 
   [ { relay.cs.net | unido.uucp } ]             | Lebensmittelwerke GmbH"

pl@etana.tut.fi (Lehtinen Pertti) (09/28/89)

From article <12070@cit-vax.Caltech.Edu>, by wen-king@cit-vax.Caltech.Edu (King Su):
> 
> #define bool(a) (!!(a))
> 
> Then just use bool(X) whenever you wanted to use (bool)X.
> 

	Then suddenly just behind the corner cames C-compiler from
	ACME-corporation and realizes '!!a' -> negation of negation is
	same as original -> we can optimize it away.

	Nice, isn't it.  And too real too.

--
pl@tut.fi				! All opinions expressed above are
Pertti Lehtinen				! purely offending and in subject
Tampere University of Technology	! to change without any further
Software Systems Laboratory		! notice

quiroz@cs.rochester.edu (Cesar Quiroz) (09/28/89)

In <8862@etana.tut.fi>, pl@etana.tut.fi (Lehtinen Pertti) suggested
that the bogus "optimization"
| 	Then suddenly just behind the corner cames C-compiler from
| 	ACME-corporation and realizes '!!a' -> negation of negation is
| 	same as original -> we can optimize it away.
could make !!a be just good old a, instead of guaranteed 0 or 1.

Either such compiler exists, in whose case it is broken and we
should not lose much sleep over it, or it doesn't.  My impression is
that it doesn't, barring better information from the poster.   That
would be a really poor case of arguing from the incompetence of a
non-existent compiler.  Madness lies that way; opposing or
supporting something just because some compiler could, perhaps,
maybe, if we try hard enough, screw up the language is ridiculous.

If you know of a compiler that makes that mistake, expose it to the
community, that may get it fixed (or at least may make it reasonable
to be extra cautious when having to use the critter).  Else, please
don't invent it just for the sake of argument.
-- 
                                      Cesar Augusto Quiroz Gonzalez
                                      Department of Computer Science
                                      University of Rochester
                                      Rochester,  NY 14627

jeenglis@nunki.usc.edu (Joe English) (09/29/89)

pl@etana.tut.fi (Lehtinen Pertti) writes:
>From article <12070@cit-vax.Caltech.Edu>, by wen-king@cit-vax.Caltech.Edu (King Su):
>> #define bool(a) (!!(a))
>> 
>> Then just use bool(X) whenever you wanted to use (bool)X.
>	Then suddenly just behind the corner cames C-compiler from
>	ACME-corporation and realizes '!!a' -> negation of negation is
>	same as original -> we can optimize it away.

But that won't happen with a working compiler, since
!!a is not equivalent to a.

This macro doesn't solve the perceived problem,
though:  what is wanted is a first-class boolean type
(don't ask me what it was wanted *for*, I don't
know...) This solution requires explicit casting of
every boolean expression.

--Joe English

  jeenglis@nunki.usc.edu.

tim@cayman.amd.com (Tim Olson) (09/29/89)

In article <8862@etana.tut.fi> pl@etana.tut.fi (Lehtinen Pertti) writes:
| From article <12070@cit-vax.Caltech.Edu>, by wen-king@cit-vax.Caltech.Edu (King Su):
| > 
| > #define bool(a) (!!(a))
| > 
| > Then just use bool(X) whenever you wanted to use (bool)X.
| > 
| 
| 	Then suddenly just behind the corner cames C-compiler from
| 	ACME-corporation and realizes '!!a' -> negation of negation is
| 	same as original -> we can optimize it away.
| 
| 	Nice, isn't it.  And too real too.

And wrong, too.  Do you know of a compiler that does this in the
general case?

	-- Tim Olson
	Advanced Micro Devices
	(tim@amd.com)

diamond@csl.sony.co.jp (Norman Diamond) (09/29/89)

From article <12070@cit-vax.Caltech.Edu>, by wen-king@cit-vax.Caltech.Edu (King Su):

>> #define bool(a) (!!(a))
>> Then just use bool(X) whenever you wanted to use (bool)X.

In article <8862@etana.tut.fi> pl@etana.tut.fi (Lehtinen Pertti) writes:

>	Then suddenly just behind the corner comes C-compiler from
>	ACME-corporation and realizes '!!a' -> negation of negation is
>	same as original -> we can optimize it away.

Actually no.  If the optimizer reduces this to a no-op without knowing
that "a" must already be 0 or 1, then the optimizer is broken.  "!"
was required to produce a result of 0 or 1 even before K&R-1.

-- 
Norman Diamond, Sony Corporation (diamond@ws.sony.junet)
  The above opinions are inherited by your machine's init process (pid 1),
  after being disowned and orphaned.  However, if you see this at Waterloo or
  Anterior, then their administrators must have approved of these opinions.

condict@cs.vu.nl (Michael Condict) (09/29/89)

In article <12070@cit-vax.Caltech.Edu> wen-king@cit-vax.UUCP (Wen-King Su) writes:
>In article <393@cpsolv.UUCP> rhg@cpsolv.uucp (Richard H. Gumpertz) writes:
>>The biggest advantage of a built-in boolean type would be that casts TO it
><would test for zero/non-zero rather than just trucating the high-order bits
>>if sizeof(source) is bigger than sizeof(bool).  Also,  . . .
>
>Why not just do:
>
>#define bool(a) (!!(a))
>
>Then just use bool(X) whenever you wanted to use (bool)X.
>

Because neither lint nor the C compiler will help you find the places where
you forgot to use bool(X).  Presumably, ints would be cast to the proposed
Boolean type automatically, as needed.  Or the two types would be incompatible
and require an explicit cast to avoid an error message (except when ints are
used in the bool-expr of a while loop or if statement).

One of the biggest problems with C, compared to strongly typed languages
like Pascal, is that it doesn't help you enough in finding type mismatch
errors.  ANSI C does not solve this problem completely, although its
function prototypes at least allow compilers to do their weak type checking
across function boundaries, as well as within a single compilation unit.
Unfortunately the only cases for which the weak type checking produces error
messages is when pointers and numeric types, or two different pointer types,
are mixed.

Consider the case where you have a function that expects a float, an int and
a char.  In most cases, you the programmer consider these to be different,
incompatible types, and would consider it an error to pass a character
constant in the place where the float is expected.  This would almost cer-
tainly indicate that the caller got the order of the parameters wrong.
C, on the other hand, happily (and quietly) converts the character, which
is a numeric type, to a float, in the presence of a prototype.  In the absence
of a prototype, lint will complain about the mismatch of the char and float,
but will not complain if you get the order of the char and int parameter
wrong.

The issue is this: is a programming language always more powerful when it
accepts a given construct, rather than rejecting it with an error message?
Or is it sometimes weaker?  Opinions differ when specific constructs are
discussed, but I doubt if anyone would want to go back to the bad old
days when integers and pointers were compatible types and could be
interchanged freely.

Michael Condict    condict@cs.vu.nl
Vrije University

bright@Data-IO.COM (Walter Bright) (09/30/89)

In article <8862@etana.tut.fi> pl@etana.tut.fi (Lehtinen Pertti) writes:
<From article <12070@cit-vax.Caltech.Edu>, by wen-king@cit-vax.Caltech.Edu (King Su):
<< #define bool(a) (!!(a))
<	Then suddenly just behind the corner cames C-compiler from
<	ACME-corporation and realizes '!!a' -< negation of negation is
<	same as original -< we can optimize it away.
If a compiler thought that (!!a) == (a), then it is a compiler bug.
<	Nice, isn't it.  And too real too.
If you run up against such wretchedness, you can do this:

#if ACME_C
#define bool(a)	((a) != 0)	/* if desperate try ((a)?1:0)	*/
#else
#define bool(a) (!!(a))
#endif

I have a copy of K&R which I believe is a first printing. It *clearly*
states that ! is to return 1 or 0. Not -1. Not implementation defined.
Using ! is portable. If it doesn't work with your C, treat it like any
other compiler bug.

If anyone knows of a *current* C compiler that has a problem with this,
please email me. I'm curious!

news@cs.yale.edu (Usenet News) (09/30/89)

>vojon ol mi komence imagis.  ^Cu        pletely different from what I first
>ne unu el la precipaj avanta^goj        imagined.  Wouldn't one of the main
>de C-tipo `boolean' estus, ke ^gi       advantages of a `boolean' type in C
>ebligus pli striktan kontrolon de       be the possibility for stricter type
>tipoj (pli ol la ^sparo de kelkaj       checking (rather than saving a few
>bitoj)?  Kompreneble, tiuj belaj        bits)?  Of course, such beloved con-
>konstrua^joj "x<y<z<u" tiam ne          structs as "x<y<z<u" would no longer
>estus eblaj, se ne permesi ankaw        be possible, unless comparison of
>komparon de bule-oj.                    `boolean's would be permitted.
From: zador-anthony@CS.YALE.EDU (anthony zador)
Path: zador-anthony@CS.YALE.EDU

OK, i'll bite. Esperanto?

lsmith@apollo.HP.COM (Lawrence C. Smith) (10/03/89)

In article <2142@dataio.Data-IO.COM> bright@dataio.Data-IO.COM (Walter Bright) writes:
>In article <9464@attctc.Dallas.TX.US> wjf@attctc.Dallas.TX.US (Jesse Furqueron) writes:
><In article <13730@well.UUCP>, nagle@well.UUCP (John Nagle) writes:
><<      I would like to suggest that the time has come to standardize the
><< Boolean values in C.  Most programs have definitions of these, but they
><< differ and clash.
><I would suggest rather than FALSE = 0 and TRUE = 1, that the "real" definition
><of TRUE is not FALSE (TRUE = not 0), i.e. TRUE = !0.
>
>What's the point? !0 == 1. Period. It is not going to change. !0 is not
>more portable or more readable.

Sadly, many C hackers just don't realize how important a clear, readable style is.
This last comment reminds of the other fellow who also felt that, because ints *could*
be used for booleans then that was *good* and there was no point making things more
"complicated".  Perhaps these people would also like BLISS, which reduces the number
of essential data types to just one...
>
>I used to extensively use:
>	typedef int bool;
>	#define TRUE 1
>	#define FALSE 0
>I eventually gave this up because:
>1. Name space collisions with other people's code.
>2. Frequent confusion of whether TRUE meant !=0 or if it really meant 1.

I use something like this:

typedef int flag;
#define YES (1==1)
#define NO  (1==0)
#define OKAY(x) ((x) != 0)

The use of YES, NO, OKAY and flag do not seem to generate much conflict with other
people's choices, and the YES and NO macros are guaranteed portable (and I obviously
depend on the optimizer to turn (1==1) into the appropriate internal TRUTH value).
Since YES and NO always equate to whatever internal values the compiler likes, and
since most compilers *will* do constant folding, these work out pretty efficiently.
Also, I can now save boolean expressions:

   flag foo;
   foo = A == B;

With the fairly certain knowledge that if(foo) (or the somewhat ridiculous
if(foo == YES)) will work consistantly and correctly.  OKAY is used for old
C code:

   foo = OKAY(strcmp("fubar",some_silly_string))
   if(foo) ...

It's not as good as a rigorously defined built-in type with compiler checking and
the like, buts it *is* better than just using 0 and 1 with ints.

>   Note that functions like isalpha() return !=0 or 0, not 1 or 0. This
>   means that if you wish to precisely use TRUE/FALSE, you have to write code
>   like
>	condition = (isalpha(c) != 0);
>   which is an efficiency problem.

It is like fun.  I will grant you that C has twelve ways of doing something because
they are, in theory, compiled differently and that some ways are more efficient than
others in certain contexts and that the programmer has the power to choose.  But this
is the modern world!!!  In this enlightened day and age, we know that 90% of the
execution time is in 10% of the code, and that optimizing code executed once buys
nothing.  In this enlightened day and age, we know that optimizers will fold, spindle
and mutilate our code, and that most of the time the optimizers know more about
efficient instruction sequences on CPU x than we do, and that's the way it should be.
In this enlightened day and age, we know that condition  = (isalpha(c) != 0) will
very seldom be an efficiency problem, even assuming the compiler really compiles it
that way.

>P.S. One of my pet peeves is code like:
>	#ifdef notdefined
>instead of
>	#if 0
>For the former, I have to grep all the c, h and makefiles to make sure
>notdefined is never defined. For the latter, there can be no problem.
>Ditto for stuff like
>	while (ALWAYS)
>	loop_forever
>instead of
>	while (1)

You choose your idiom and you use it.  Where I come from, people who write
while (1) would be castigated, flagellated and fumigated for not having written
for(;;).  In other places, you would be taken to task for not writing while(1),
or whatever.  C has too many different ways of doing things for any of them to
be universal without enforcement from training institutions, of which we ain't
got.  for(;;) was the Stony Brook way, so that's what I learned.  Is it still that
way?  Who knows.  It might be, if the same guy is teaching the course.  Or maybe
they have a new former Berkley guy who likes while(1) or while (1).  Of course,
they might also have a new wave guy who likes "#define loop while(1) ... loop ..."
or even a FORTRAN retread who simply does a "go to loop" at the bottom of his
loop.

If you want consistant, use Pascal.

-- 
Larry Smith
  Internet: lsmith@apollo.hp.com
  UUCP:     {decvax,mit-eddie,umix}!apollo!lsmith

lsmith@apollo.HP.COM (Lawrence C. Smith) (10/03/89)

In article <27541@amdcad.AMD.COM> tim@amd.com (Tim Olson) writes:
>In article <8862@etana.tut.fi> pl@etana.tut.fi (Lehtinen Pertti) writes:
>| From article <12070@cit-vax.Caltech.Edu>, by wen-king@cit-vax.Caltech.Edu (King Su):
>| > 
>| > #define bool(a) (!!(a))
>| > 
>| > Then just use bool(X) whenever you wanted to use (bool)X.
>| > 
>| 
>| 	Then suddenly just behind the corner cames C-compiler from
>| 	ACME-corporation and realizes '!!a' -> negation of negation is
>| 	same as original -> we can optimize it away.
>| 
>| 	Nice, isn't it.  And too real too.
>
>And wrong, too.  Do you know of a compiler that does this in the
>general case?

Yes, all of them.  This is an example of a "cheap" optimization, one that
is relatively easy and safe, most of the time.  The fact that it does not
do what we would expect does not mean it is wrong, either.  !!a == a under
the compiler's own built-in logical rules and if(a) will work the same way.
I don't think there is a compiler in the world I'd trust to take !!a and
turn it into a canonical true/false value.  Come on, people!  C compilers
weren't even required to honor parens until the last ANSI revision, a C
compiler is allowed to do *anything it wants* to a program provided the
final program is congruent to the input program with repect to the compilers
own rules for such changes.  No compiler has to compile a++ if ++a gives
the same result.  No compiler has to compile (a++; b = a-1;) when (b = a++;)
means the same thing.  This isn't new, the floating point fans have been
bitching about this for *years* since it makes C terribly unsafe for
floating point, where round-off can smite you a mighty blow without warning.

Folks, all this is all just adding weight to the "let's add booleans to C"
contingent's argument.
-- 
Larry Smith
  Internet: lsmith@apollo.hp.com
  UUCP:     {decvax,mit-eddie,umix}!apollo!lsmith

bart@videovax.tv.Tek.com (Bart Massey) (10/04/89)

In article <45fe2dd3.1199f@apollo.HP.COM> lsmith@apollo.HP.COM (Lawrence C. Smith) writes:
> In article <27541@amdcad.AMD.COM> tim@amd.com (Tim Olson) writes:
> >In article <8862@etana.tut.fi> pl@etana.tut.fi (Lehtinen Pertti) writes:
> >| 	Then suddenly just behind the corner cames C-compiler from
> >| 	ACME-corporation and realizes '!!a' -> negation of negation is
> >| 	same as original -> we can optimize it away.
> >| 
> >| 	Nice, isn't it.  And too real too.
> >
> >And wrong, too.  Do you know of a compiler that does this in the
> >general case?
> 
> Yes, all of them.

Aiigh!  I'm sure I'm about the millionth response to this, but I just
can't stand it anymore!

	"The result of the logical negation operator ! is
	1 if the value of its operand is 0, 0 if the value
	of its operand is non-zero.  The type of the
	result is int.  It is applicable to any arithmetic
	type or to pointers"  -- K&R A:7.2, Stroustrup r.7.2

	"The result of the logical negation operator ! is 0
	if the value of its operand compares unequal to 0,
	1 if the value of its operand compares equal to 0.
	The result has type int.  The expression !E is
	equivalent to (0==E)." -- ANSI X3J11/88-158 3.3.3.3 19

So anything that is supposed to be a standard C or C++ compiler
is *required* to do the right thing!  As a test, I tried 4 C compilers
we have around:

	Stanford's V6.0 68k (an ancient PCC based compiler)
	Greenhills 68k (a modern commercial compiler)
	BSD 4.3Tahoe VAX (a modern PCC based compiler)
	GNU GCC1.34 VAX (a cool highly optimizing retargetable compiler)

The test code I used was simply:

	/* test.c */
	main( argc, argv )
	int argc;
	char **argv;
	{
	    printf( "%d\n", (!!(atoi(argv[1]))) );
	}

All compilers, when invoked with "$(CC) $(MISCFLAGS) -O -o test test.c",
produced a binary for which the invocation "./test 2" printed
"1".  Examination of the assembly code revealed various levels of
optimization, but no obvious incorrect code.

> This is an example of a "cheap" optimization, one that
> is relatively easy and safe, most of the time.  The fact that it does not
> do what we would expect does not mean it is wrong, either.

No, the fact that it does not conform to any accepted C	language
definition means that it is wrong.  Note that your optimization *is*
legal if the compiler can somehow tell that it is completely invisible
-- the "as-if" rule.  I.e., one can legally optimize
	if( !!a )
		printf( "hello\n" );
to
	if( a )
		printf( "hello\n" );
because the second statement behaves as if it were the first in all
cases...

Enough said.  Please try writing some C code before making strong
statements about the foibles of existing C compilers.  I know of no
compiler which will compile my test program above into incorrect code
because of a bug involving the optimization of the "booleanizing
operator" (sic :-) "!!".  If anyone could give me an example of any such
compiler that I could independently verify, I'd be truly interested.

					Bart Massey
					..tektronix!videovax.tv.tek.com!bart
					..tektronix!reed.bitnet!bart