[comp.lang.c] TRUE and FALSE

ark@alice.UUCP (Andrew Koenig) (08/21/90)

In article <12249@netcom.UUCP>, ergo@netcom.UUCP (Isaac Rabinovitch) writes:

> On the other hand, you can say (and I used to) that using 1 and
> 0 instead of TRUE and FALSE is a similar "familiar practice", since any
> competant C programmer knows that C booleans are just integers.  
> In this case it probably makes a big difference that TRUE and FALSE are
> ordinary English words, not obscure acronyms.

Unfortunately, using TRUE and FALSE opens a great gaping hole:
one would expect that

	x == TRUE

would mean the same as

	x != FALSE

but of course it doesn't -- at least not if you use the usual C
convention that 0 is false and any other value is true.

> I recently came up against a similar clash of "familiar concepts" in
> C.  People were arguing (was it in this group?) over why programmers
> use "i" instead of "i == 0".

Well, for one thing,

	if (i) foo();

and

	if (i == 0) foo();

mean precisely the opposite of each other.  :-)
-- 
				--Andrew Koenig
				  ark@europa.att.com

kdq@demott.COM (Kevin D. Quitt) (08/22/90)

In article <11215@alice.UUCP> ark@alice.UUCP (Andrew Koenig) writes:
>In article <12249@netcom.UUCP>, ergo@netcom.UUCP (Isaac Rabinovitch) writes:
>
>> On the other hand, you can say (and I used to) that using 1 and
>> 0 instead of TRUE and FALSE is a similar "familiar practice", since any
>> competant C programmer knows that C booleans are just integers.  
>> In this case it probably makes a big difference that TRUE and FALSE are
>> ordinary English words, not obscure acronyms.
>
>Unfortunately, using TRUE and FALSE opens a great gaping hole:
>one would expect that
>
>	x == TRUE
>
>would mean the same as
>
>	x != FALSE
>
>but of course it doesn't -- at least not if you use the usual C
>convention that 0 is false and any other value is true.


    We use 

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

    defined that way for hysterical raisins (broken compiler).  We are
aware of the problem above, and never test booleans that way.  TRUE and
FALSE are used for assignment purposes only.  It makes the intent of the
code more obvious. 

-- 
 _
Kevin D. Quitt         demott!kdq   kdq@demott.com
DeMott Electronics Co. 14707 Keswick St.   Van Nuys, CA 91405-1266
VOICE (818) 988-4975   FAX (818) 997-1190  MODEM (818) 997-4496 PEP last

                96.37% of all statistics are made up.

david@csource.oz.au (david nugent) (08/28/90)

In <514@demott.COM> kdq@demott.COM (Kevin D. Quitt) writes:

> >Unfortunately, using TRUE and FALSE opens a great gaping hole:
> >one would expect that
> >
> >	x == TRUE
> >
> >would mean the same as
> >
> >	x != FALSE
> >
> >but of course it doesn't -- at least not if you use the usual C
> >convention that 0 is false and any other value is true.

> We use 

> #define	TRUE	(1==1)
> #define	FALSE	(1!=1)

>     defined that way for hysterical raisins (broken compiler).  We are
> aware of the problem above, and never test booleans that way.  TRUE and
> FALSE are used for assignment purposes only.  It makes the intent of the
> code more obvious. 


Shouldn't

 # define FALSE 0
 # define TRUE  (!FALSE)
 
_always_ work?

I have been using this for a considerable amount of time, and so far
haven't seen any problems with it.  Or are there some circumstances
where this might not cover all cases?

Regards,

david


-- 

        Fidonet: 3:632/348   SIGnet: 28:4100/1  Imex: 90:833/387
              Data:  +61-3-885-7864   Voice: +61-3-826-6711
 Internet/ACSnet: david@csource.oz.au    Uucp: ..!uunet!munnari!csource!david

dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) (08/28/90)

In <514@demott.COM> kdq@demott.COM (Kevin D. Quitt) writes:

     TRUE and FALSE are used for assignment purposes only.  It makes
     the intent of the code more obvious.

When I find somebody who really, really, really wants to define TRUE
and FALSE, even somebody who uses them for assignment only, I recommend
the following defines instead:

     #define ZERO   0
     #define ONE    1

These are so much more clear than TRUE and FALSE, and if you use
them in a test, you know exactly what you're testing!
--
Rahul Dhesi <dhesi%cirrusl@oliveb.ATC.olivetti.com>
UUCP:  oliveb!cirrusl!dhesi

volpe@underdog.crd.ge.com (Christopher R Volpe) (08/28/90)

In article <2316@cirrusl.UUCP>, dhesi%cirrusl@oliveb.ATC.olivetti.com
(Rahul Dhesi) writes:
|>
|>When I find somebody who really, really, really wants to define TRUE
|>and FALSE, even somebody who uses them for assignment only, I recommend
|>the following defines instead:
|>
|>     #define ZERO   0
|>     #define ONE    1
|>

Ugh. Those say nothing. They don't hint to the boolean nature of the
variables being assigned to. They're as useless as the comments in
the following code:

   main()
   {
     int i; /* declare variable i */
     i=0; /* assign zero to i */
     while (!EOF) { /* while not end of file */
       i=i+1; /* increment i by one */
       if (i>100) /* if i is greater than 100 */
         i=0; /* then reset i to zero */
     }
   }
                 
==================
Chris Volpe
G.E. Corporate R&D
volpecr@crd.ge.com

flint@gistdev.gist.com (Flint Pellett) (08/29/90)

volpe@underdog.crd.ge.com (Christopher R Volpe) writes:

>In article <2316@cirrusl.UUCP>, dhesi%cirrusl@oliveb.ATC.olivetti.com
>(Rahul Dhesi) writes:
>|>
>|>When I find somebody who really, really, really wants to define TRUE
>|>and FALSE, even somebody who uses them for assignment only, I recommend
>|>the following defines instead:
>|>
>|>     #define ZERO   0
>|>     #define ONE    1
>|>

>Ugh. Those say nothing. They don't hint to the boolean nature of the
>variables being assigned to.

I agree.  They may also get you into trouble should you ever wish to change
the values of your booleans: Off-hand, I don't know why you would want to,
but it is possible that at some point in the future you might have to port
to CBD C (Charlie's Brain-Dead C) where TRUE is -1, and you'd be rather
embarassed to have this line in your code:

#define	ONE	-1

From a true-to-life example of why names like the above are bad:
an old program for a SYSV file system, which knew it needed 14 chars for
file names at each level, and was putting 2 character extensions (like
".c" elsewhere), did this:

#define  TWO        2
#define  TWELVE    12
char base_filename[TWELVE];
char filename_ext[TWO];

Then, sure enough, someone wanted it to handle file names it hadn't been
set up to handle, (which it should have handled in the first place, but
that's another story) like ones with more than 1 character extensions,
and with null-terminated names, etc., and we had this in the code:

#define  TWO	   15
#define  TWELVE    15

A few years from now (if the program had survived- I killed it; It was
a mercy killing) if it had migrated to a BSD file system, we might have
seen this:

#define  TWELVE   256

Please: pick names for constants that say what they are for, (like
CharsPerFilenameLevel) not what they are, because what they are for is
not going to change, the values might.  You'll also avoid ending up with
someone using the same constant for two different meanings because the
name isn't good enough to prevent it.  (If a name like ONE got used
throughout a program to represent both boolean TRUE and buffers that
needed to be 1 char long, and you wanted to lengthen the buffers, you'd
have a nice mess to sort out.)
-- 
Flint Pellett, Global Information Systems Technology, Inc.
1800 Woodfield Drive, Savoy, IL  61874     (217) 352-1165
uunet!gistdev!flint or flint@gistdev.gist.com

asrap@warwick.ac.uk (Sean Legassick) (08/29/90)

In article <2316@cirrusl.UUCP> dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) writes:
=In <514@demott.COM> kdq@demott.COM (Kevin D. Quitt) writes:
=
=     TRUE and FALSE are used for assignment purposes only.  It makes
=     the intent of the code more obvious.
=
=When I find somebody who really, really, really wants to define TRUE
=and FALSE, even somebody who uses them for assignment only, I recommend
=the following defines instead:
=
=     #define ZERO   0
=     #define ONE    1
=
=These are so much more clear than TRUE and FALSE, and if you use
=them in a test, you know exactly what you're testing!

	This has to be one of the most useless suggestions I have read on
this newsgroup. How about some more defines:

	#define TWO 2
	#define THREE 3
	#define FOUR 4
	....
	#define NINE 9

	And how about some more:

	#define EQUALS ==
	#define LESSTHAN <	...... ad infinitum

	Okay, so maybe I'm going over the top a little - but you get my point.
Personally I go further than simply using TRUE and FALSE (which by the way
I always define as (1==1) and (1==0), not for portability but for a little
extra clarity and any compiler worth its salt will optimise them down anyway).
	I have in a standard header file a typedef for bool (which I typedef
to an int, although if I used ANSI extensions I could add even more clarity
and typedef to an enum { false, true }. This I find is invaluable for
clarities sake. An int declaration says to me this variable is going to hold
a scalar value - which is very different from a boolean one.
	I would be interested in anyone who thinks an int declaration of
a boolean variable is clearer. The only argument against my method I can think
of is that of standardisation - bool isn't a standard C type and shouldn't
be as it is still basically an int. However of all the additional types
I have seen in people's source, bool is the one I've seen most often.

---------------------------------------------------------------------------
Sean Legassick,       cuuee@uk.ac.warwick.cu  "Improbability factor of one
Computing Services    asrap@uk.ac.warwick.cu    to one. We have normality.
University of Warwick      	 	         Anything you still can't
            (the walking C obfuscator!)	 	  handle is your own problem."

jak@sactoh0.SAC.CA.US (Jay A. Konigsberg) (08/30/90)

In article <2316@cirrusl.UUCP> dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) writes:
>In <514@demott.COM> kdq@demott.COM (Kevin D. Quitt) writes:
>>
>>TRUE and FALSE are used for assignment purposes only.  It makes
>>the intent of the code more obvious.
>
>When I find somebody who really, really, really wants to define TRUE
>and FALSE, even somebody who uses them for assignment only, I recommend
>the following defines instead:
>
>     #define ZERO   0
>     #define ONE    1
>
>These are so much more clear than TRUE and FALSE, and if you use
>them in a test, you know exactly what you're testing!
>--

Pish-posh! TRUE and FALSE are much clearer. Kevin is correct when
he says TRUE and FALSE are used for assignment purposes only. The
resulting values are then easly checked in standard C syntax making
the code more self-documentating.

Personally though, I like the following:

#define TRUE -1

Why? Because of the following 8 bit pattern:

 1: 01111111
-1: 11111111

I mean, after all, if I'm going to set one I might as well set all :-)

-- 
-------------------------------------------------------------
Jay @ SAC-UNIX, Sacramento, Ca.   UUCP=...pacbell!sactoh0!jak
If something is worth doing, its worth doing correctly.

chip@tct.uucp (Chip Salzenberg) (08/30/90)

According to flint@gistdev.gist.com (Flint Pellett):
>[...] it is possible that at some point in the future you might have to
>port to CBD C (Charlie's Brain-Dead C) where TRUE is -1 [...]

It makes no sense to dispute the portability of the definitions
"#define TRUE 1" and "#define FALSE 0".  If you can't count on
"(1==1)==1" and "(1==0)==0" then you're not using C.

The readability and maintainability of code using TRUE and FALSE,
however, are still issues.  Personally, I like them; but then, I
detest the One True Brace Style, so what do I know?  :-)
-- 
Chip Salzenberg at Teltronics/TCT     <chip@tct.uucp>, <uunet!pdn!tct!chip>

chris@mimsy.umd.edu (Chris Torek) (08/30/90)

>>In <514@demott.COM> kdq@demott.COM (Kevin D. Quitt) writes:
>>>TRUE and FALSE are used for assignment purposes only.  It makes
>>>the intent of the code more obvious.

>In article <2316@cirrusl.UUCP> dhesi%cirrusl@oliveb.ATC.olivetti.com
(the much-misunderstood Rahul Dhesi) writes:
[yes, you have seen it before, but this time read it with a `sarcastic
face' in mind]
>>When I find somebody who really, really, really wants to define TRUE
>>and FALSE, even somebody who uses them for assignment only, I recommend
>>the following defines instead:
>>
>>     #define ZERO   0
>>     #define ONE    1
>>
>>These are so much more clear than TRUE and FALSE, and if you use
>>them in a test, you know exactly what you're testing!

In article <3835@sactoh0.SAC.CA.US> jak@sactoh0.SAC.CA.US (Jay A. Konigsberg)
misses the scarcasm:
>Pish-posh! TRUE and FALSE are much clearer. Kevin is correct when
>he says TRUE and FALSE are used for assignment purposes only. The
>resulting values are then easly checked in standard C syntax making
>the code more self-documentating.
>
>Personally though, I like the following:
>
>#define TRUE -1

Since this is all going around again (already!), it is probably time
for a small addition to the FAQ list:

Q: How about Booleans in C?  For instance:

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

A: Some people believe this adds clarity.  Beware, however:

	typedef enum { true, false } bool;	/* bug */

	bool result;
	result = a == b;

   Surprise, this sets `result' to `true' if a!=b, and to `false'
   if a==b.  Or consider

	#define FALSE 0
	#define TRUE -1

	if ((a == b) == TRUE) ...

   This `if' test never runs.  Or:

	if (x) ...
   vs	if (x == TRUE) ...
   vs	if (x != FALSE) ...

   The middle line does something different from the first and last
   lines.

Q: What about

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

   Since C defines the RESULT of all boolean operators as 0-for-false
   and 1-for-true (but does not make such a requirement on the TEST
   value in if, while, etc.), this is needless make-work for the compiler.
   Some people have suggested that this is useful with broken compilers
   (where `true' results produce the value -1, for instance), but if
   the compiler gets something this basic wrong, how can you trust it
   to produce correct code for anything even moderately complicated?

   These defines still suffer from the problem that `x==TRUE' means
   something different from `x!=FALSE'.

   As a final note, the `best' choice of storage type for a boolean
   is not necessarily `int' (in some situations a bit array would be
   best, although C does not provide such directly).  If you use an
   enumerated type, the storage type is up to the compiler; however,
   the compiler is then free to warn about
   	bool x = a == b;
   since the result of `a==b' is an `int' and not an enumeration
   member.  (The compiler must accept the expression; it may only
   generate a warning at most.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

peter@ficc.ferranti.com (Peter da Silva) (08/30/90)

In article <3835@sactoh0.SAC.CA.US> jak@sactoh0.SAC.CA.US (Jay A. Konigsberg) writes:
> #define TRUE -1

This is C, not Forth. The truth value returned by comparison operators is
defined to be "1".
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.   'U`
peter@ferranti.com

volpe@underdog.crd.ge.com (Christopher R Volpe) (08/31/90)

I wouldn't use TRUE and FALSE in comparisons such as if (x==TRUE)
for the reasons Chris Torek outlined, but I think they are useful
for setting default values, e.g. "int expert_mode = TRUE;".

For tests, if you want the extra clarity, how about the following:
#define TRUE(x) (x)
#define FALSE(x) (!(x))

and then do things like " if (FALSE((x==y) && (x==z)) || whatever) ..."
==================
Chris Volpe
G.E. Corporate R&D
volpecr@crd.ge.com

bomgard@copper.ucs.indiana.edu (Tim Bomgardner) (08/31/90)

In article <1990Aug29.153917.28110@warwick.ac.uk> asrap@warwick.ac.uk (Sean Legassick) writes:
>[...]
>	And how about some more:
>
>	#define EQUALS ==
>	#define LESSTHAN <	...... ad infinitum

You're gonna laugh, but I never got Fortran out of my system (so to
speak).  After a couple coding errors early in my C career of the form 

  if (x = y) ...  and
  if (x << y) ...

I put the following defines in a .h file:

  #define EQ ==
  #define NE !=
  #define LT <
  #define NOT !
  #define AND &&
  #define OR ||
  etc.

Another guy I know went even further, with defines such as

  #define THEN {
  #define ELSE } else {
  #define ENDIF }
  etc.

It actually made converting a lot of old fortran programs to C go pretty
quickly.

>	Okay, so maybe I'm going over the top a little - but you get my point.
>Personally I go further than simply using TRUE and FALSE (which by the way
>I always define as (1==1) and (1==0), not for portability but for a little
>extra clarity and any compiler worth its salt will optimise them down anyway).
>	I have in a standard header file a typedef for bool (which I typedef
>to an int, although if I used ANSI extensions I could add even more clarity
>and typedef to an enum { false, true }. This I find is invaluable for
>clarities sake. An int declaration says to me this variable is going to hold
>a scalar value - which is very different from a boolean one.
>	I would be interested in anyone who thinks an int declaration of
>a boolean variable is clearer. The only argument against my method I can think
>of is that of standardisation - bool isn't a standard C type and shouldn't
>be as it is still basically an int. However of all the additional types
>I have seen in people's source, bool is the one I've seen most often.

Well, depending on how you look at it, *everything* is an int (of one
length or another).  That's no reason to eliminate a data type.  Data
abstraction is one of the reasons we use high level languages in the
first place.  typedef bool makes perfect sense and is in keeping with
the C tradition of never spelling any word out if it can be avoided (if
u cn rd ths, u cn wrt pgms n C).  And for all you fortran fans out
there, how bout

  #define LOGICAL int

(yes, that's there in my friend's .h file, as well as INTEGER, REAL,
etc.).

I DEFINE all my case labels, magic numbers, etc., and more often than
not my variable names have more than 12 characters instead of less.  At
least I can look at code I wrote a couple years ago with a good chance
that I'll have some clue as to what it was I thought I was doing.

browns@iccgcc.decnet.ab.com (Stan Brown, Oak Road Systems) (08/31/90)

In article <26280@mimsy.umd.edu>, chris@mimsy.umd.edu (Chris Torek) writes:
> Since this is all going around again (already!), it is probably time
> for a small addition to the FAQ list:
> 
> Q: How about Booleans in C?  For instance:
> 
> 	typedef int bool;
> 	#define FALSE 0
> 	#define TRUE 1
> 
> A: Some people believe this adds clarity.  Beware, however:
> 
> 	typedef enum { true, false } bool;	/* bug */
> 
[rest of excellent comments deleted]

Chris, I think adding this to the FAQ's is an excellent idea.  I like the way
you said in your post that it's not settled whether int or enum is better for
this. Only suggestion I'd make: you tell how _not_ to write the enum; why not
also tell how to write it:

	typedef enum {false, true} bool;

Stan Brown, Oak Road Systems, Cleveland, Ohio, U.S.A.         (216) 371-0043
The opinions expressed are mine. Mine alone!  Nobody else is responsible for
them or even endorses them--except my cat Dexter, and he signed the power of
attorney only under my threat to cut off his Cat Chow!

lfd@cbnewsm.att.com (leland.f.derbenwick) (08/31/90)

In article <11369@crdgw1.crd.ge.com>,
volpe@underdog.crd.ge.com (Christopher R Volpe) writes:
> In article <2316@cirrusl.UUCP>, dhesi%cirrusl@oliveb.ATC.olivetti.com
> (Rahul Dhesi) writes:
> |>
> |>When I find somebody who really, really, really wants to define TRUE
> |>and FALSE, even somebody who uses them for assignment only, I recommend
> |>the following defines instead:
> |>
> |>     #define ZERO   0
> |>     #define ONE    1
> |>
> 
> Ugh. Those say nothing. They don't hint to the boolean nature of the
> variables being assigned to. They're as useless as the comments in
> the following code: [deleted]

Am I the only one out here who thought that "Those say nothing" was
_exactly_ the point of the posting?

I saw the ZERO/ONE posting as a parody of the TRUE/FALSE suggestion,
pointing out gently that #defining TRUE and FALSE is about as useful
as ONE and ZERO -- they are hacks for people who don't approve of
the original choice made when the language was invented.

And defining TRUE and FALSE tends to lead, eventually, to some
maintenance programmer who's just (almost) learned C writing

   if (flag == TRUE)

which of course doesn't work at all the way it looks.  (Though I'll
admit it reads well: "if flag is true...")  IMHO, any "improvement"
that would lead a novice into this sort of error is a step backwards.

Of course, this is now the <n+1>st rehashing of this issue in this
newsgroup, and it's essentially become a religious war.

 -- Speaking strictly for myself,
 --   Lee Derbenwick, AT&T Bell Laboratories, Warren, NJ
 --   lfd@cbnewsm.ATT.COM  or  <wherever>!att!cbnewsm!lfd

karl@haddock.ima.isc.com (Karl Heuer) (08/31/90)

In article <708.26dd1bf9@iccgcc.decnet.ab.com> browns@iccgcc.decnet.ab.com (Stan Brown, Oak Road Systems) writes:
>Chris, I think adding this to the FAQ's is an excellent idea.  I like the way
>you said in your post that it's not settled whether int or enum is better for
>this. Only suggestion I'd make: you tell how _not_ to write the enum; why not
>also tell how to write it:
>
>	typedef enum {false, true} bool;

Item #47 in the FAQ already gives four ways to write it, and mentions some of
the tradeoff issues in choosing a type.  It could probably be amplified a bit,
though.

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint

dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) (08/31/90)

I was brash enough to suggest

     #define ZERO   0
     #define ONE    1

and Sean Legassick chastises me thus:

     This has to be one of the most useless suggestions I have read on
     this newsgroup.

But in fact my suggested definitions are much more useful than the
common recommendation of defining TRUE and FALSE.

No matter how careful the original programmer is, sooner or later
somebody will come along and, noticing that TRUE means true, will try
to do something like:

     i = isdigit(c);
     ...
     if (i == TRUE) ...

thereby introducing a bug.  If, on the other hand, TRUE were not defined
but ONE were available, the coder would probably do:

     i = isdigit(c);
     ...
     if (i == ONE) ...

which would immediately make him ask himself:  "The return value from
isascii() is true, but is it really 1?"

Of course, defining ONE and ZERO is fairly silly.  But defining TRUE
and FALSE is quite risky.  I'll take fairly silly over quite risky any
day.
--
Rahul Dhesi <dhesi%cirrusl@oliveb.ATC.olivetti.com>
UUCP:  oliveb!cirrusl!dhesi

dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) (08/31/90)

In <1990Aug29.153917.28110@warwick.ac.uk> asrap@warwick.ac.uk (Sean
Legassick) explains why he might want to use enum {false, true} for
booleans in C and continues:

>I would be interested in anyone who thinks an int declaration of
>a boolean variable is clearer.

It depends.  Try this:

     typedef enum {false, true} bool;
     ...
     while ((c = getc(stdin)) != EOF) {
        bool got_digit;
	got_digit = isdigit(c);
	...
	if (got_digit == true) {
	   ...
	}
     }

Since isdigit() is not guaranteed to return 0 or 1, the value of
got_digit could be something else (e.g. 4).  Then, even when got_digit
is true by C conventions (nonzero), it isn't necessarily equal to its
enumeration value "true".

No matter what you do, you cannot in C get around this:

     Although the result of a boolean condition is always 0 or 1, all
     nonzero values are considered to be true in a boolean context.
     All mechanisms that try to represent this fact using only two
     values (e.g. TRUE and FALSE, or enum {false, true}) are likely to
     lead to bad code that looks good.
--
Rahul Dhesi <dhesi%cirrusl@oliveb.ATC.olivetti.com>
UUCP:  oliveb!cirrusl!dhesi

asrap@warwick.ac.uk (Sean Legassick) (08/31/90)

In article <2342@cirrusl.UUCP> dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) writes:
=In <1990Aug29.153917.28110@warwick.ac.uk> asrap@warwick.ac.uk (Sean
=Legassick) explains why he might want to use enum {false, true} for
=booleans in C and continues:
=
=>I would be interested in anyone who thinks an int declaration of
=>a boolean variable is clearer.
=
=It depends.  Try this:
=
[code ommited which demonstrates comparison with true will not work]
=
=Since isdigit() is not guaranteed to return 0 or 1, the value of
=got_digit could be something else (e.g. 4).  Then, even when got_digit
=is true by C conventions (nonzero), it isn't necessarily equal to its
=enumeration value "true".
=
=No matter what you do, you cannot in C get around this:
=
=     Although the result of a boolean condition is always 0 or 1, all
=     nonzero values are considered to be true in a boolean context.
=     All mechanisms that try to represent this fact using only two
=     values (e.g. TRUE and FALSE, or enum {false, true}) are likely to
=     lead to bad code that looks good.

	But as has frequently been mentioned in this thread, comparison
to any #defined TRUE and FALSE, and enum { false, true } or even just
0 and 1 cannot be guaranteed to work. Therefore I use a 'bool' type but
I NEVER USE FALSE OR TRUE IN COMPARISONS. In the code you quote I would
say:
	bool foo;
	foo = isdigit(bar);
	if (foo) ...

	Guaranteed to work, and blatantly obvious what it does. There's
nothing that says if you use bool types you have to compare to TRUE or FALSE,
you don't do it without them, so why do it with them?

--------------------------------------------------------------------------
Sean Legassick,       cuuee@uk.ac.warwick.cu  "Improbability factor of one
Computing Services    asrap@uk.ac.warwick.cu    to one. We have normality.
University of Warwick      	 	         Anything you still can't
            (the walking C obfuscator!)	 	  handle is your own problem."

brad@SSD.CSD.HARRIS.COM (Brad Appleton) (08/31/90)

>And defining TRUE and FALSE tends to lead, eventually, to some
>maintenance programmer who's just (almost) learned C writing
>
>   if (flag == TRUE)
>
>which of course doesn't work at all the way it looks.  (Though I'll
>admit it reads well: "if flag is true...")  IMHO, any "improvement"
>that would lead a novice into this sort of error is a step backwards.
>
>Of course, this is now the <n+1>st rehashing of this issue in this
>newsgroup, and it's essentially become a religious war.

I thought the whole point of having a boolean type was so that one
could write:

	if ( flag1  &&  !flag2 )

instead of

	if ( flag1 == TRUE  &&  flag2 == FALSE ).

TRUE and FALSE have no place being part of this type of comparison in 
any programming language that provides a boolean type; they are only
needed for assignment. SO why do some people insist on putting them 
in logical comparisons - its redundant.

Maybe instead of #defining or enum'ing TRUE and FALSE we should
encourage doing something like:

	#define  SET(flag)   flag = 1  /* or -1 or !0 or whatever */
	#define  CLEAR(flag) flag = 0

and if you want to get fancy:

	#define  TOGGLE(flag) flag = (flag) ? 1 : 0

(or whatever macro names you prefer) and then we would never be tempted
to use them in a comparison.

It just bothers me when I see (flag == FALSE) instead of (!flag).
I guess this is the n+2 rehashing of this tripe!

______________________ "And miles to go before I sleep." ______________________
 Brad Appleton        brad@travis.ssd.csd.harris.com   Harris Computer Systems
                          ...!uunet!hcx1!brad          Fort Lauderdale, FL USA
~~~~~~~~~~~~~~~~~~~~ Disclaimer: I said it, not my company! ~~~~~~~~~~~~~~~~~~~

reino@cs.eur.nl (Reino de Boer) (08/31/90)

volpe@underdog.crd.ge.com (Christopher R Volpe) writes:

>I wouldn't use TRUE and FALSE in comparisons such as if (x==TRUE)
>for the reasons Chris Torek outlined, but I think they are useful
>for setting default values, e.g. "int expert_mode = TRUE;".

>For tests, if you want the extra clarity, how about the following:
>#define TRUE(x) (x)
>#define FALSE(x) (!(x))

>and then do things like " if (FALSE((x==y) && (x==z)) || whatever) ..."

or, how about:
#define FALSE 0
#define TRUE  1
#define BOOL( b ) ( (b) ? TRUE : FALSE )
#define NOT( b ) BOOL( !(b) )

so that
NOT( TRUE ) == FALSE
holds.

-- Reino
-- 
Reino R. A. de Boer     "We want to build the right product right, right?"
Erasmus University Rotterdam ( Informatica )
e-mail: reino@cs.eur.nl

johnb@srchtec.UUCP (John Baldwin) (09/01/90)

In article <3835@sactoh0.SAC.CA.US> jak@sactoh0.SAC.CA.US
 (Jay A. Konigsberg) writes:
>
>Personally though, I like the following:
>
>#define TRUE -1
>
>Why? Because of the following 8 bit pattern:
>
> 1: 01111111
>-1: 11111111

Aaaiigh!  Never... NEVERNEVERNEVERNEVER *ever*
   assume 1's-complement, 2's-complement, and so on!

The exception to this is when writing very machine-specific code which you
already *know* isn't going to be portable anyway.  Even then, there are
some tricks to isolate yourself from the architecture, without giving up
much.


P.S.  what architecture gives 1(decimal) == 01111111 (binary) ???

-- 
John T. Baldwin                      |  johnb%srchtec.uucp@mathcs.emory.edu
Search Technology, Inc.              | 
                                     | "... I had an infinite loop,
My opinions; not my employers'.      |  but it was only for a little while..."

dts@quad.sialis.mn.org (David T. Sandberg) (09/01/90)

In article <664@csource.oz.au> david@csource.oz.au writes:
>Shouldn't
>
> # define FALSE 0
> # define TRUE  (!FALSE)
> 
>_always_ work?

Sorry, this is no different than defining TRUE as 1... (!FALSE) is
(!0) is (1), after all.

My two cents: I define FALSE as 0 and TRUE as 1 on a regular basis,
but only use them to make assignments to flag variables more self-
documenting.  I seldom use the defines for the conditional tests of
those variables, and _never_ use them to test the zero or nonzero
condition of any function or expression which doesn't explicitly use
those same defines in yielding it's result (that means no standard
library functions or macros, for starters).  When I do need to save
the result of such things in a variable being used as a boolean, I
do so using the longer (but safer) method:

	int gotdigit = isdigit(c) ? TRUE : FALSE;

(This could be made into a BoolValue() macro if one wished to do so.
I haven't.)

It seems to me that these defines can be quite helpful and safe if
the programmer maintains some level of discipline and restraint in
deciding where it is appropriate to use them.  In fact, at the
restricted level in which they appear in my code, TRUE could be
defined as any nonzero value without adversely affecting it's
functionality.  If changing TRUE's value would break any given
expression, then that expression is one which in my opinion should
have been considered to be out of the scope of these defines in the
first place.

-- 
 \\                                 \   David Sandberg, consultant   \\
 //         "Small hats!"           /   Richfield MN                 //
 \\                                 \   dts@quad.sialis.mn.org       \\

flee@guardian.cs.psu.edu (Felix Lee) (09/02/90)

>#define BOOL( b ) ( (b) ? TRUE : FALSE )
>#define NOT( b ) BOOL( !(b) )

Personally, I use this set of macros:
#define FALSE		0
#define CNAND(a,b)	(!((a)&&(b)))
#define CNOT(a)		CNAND(a,a)
#define CXOR(a,b)	CNAND(CNAND(a,CNOT(b)),CNAND(b,CNOT(a)))
#define CEQUIV(a,b)	CNOT(CXOR(a,b))
#define COR(a,b)	CEQUIV(a,CNAND(CNOT(a),CXOR(a,b)))
#define CAND(a,b)	CXOR(COR(a,b),CXOR(a,b))
#define TRUE		COR(FALSE,CNOT(FALSE))
#define ISTRUE(a)	CAND(TRUE,a)
#define ISFALSE(a)	CNOT(ISTRUE(a))

These may unfortunately overrun some compiler or preprocessor limits
(TRUE expands to an 853 character expression, and ISFALSE(x) expands
to 203677 characters).  But they're otherwise quite portable, and I
find the prefix style much more readable than C's cryptic infix
expressions, especially when used in conjunction with a set of macros
that provide LISP-ish control structures.
--
Felix Lee	flee@cs.psu.edu

flint@gistdev.gist.com (Flint Pellett) (09/04/90)

I've received mail from a couple people flaming me for not
reading/knowing that C evaluates booleans to 0/1, when I commented
that using the named constants ZERO/ONE for boolean values was a bad
idea.  They missed my point.   I apparently also missed Rahul's point/
sarcasm-- sorry.

The fact that C evaluates booleans to 0 or 1 and always will has very
little to do with what I said in my posting.  They have assumed that a
boolean is only useful to be evaluated by C, and that is NOT true. 
(As has been demonstrated in other notes here, using it for purposes
other than assigning vars from it is generally not good.)  It is quite
possible that a program is written which contains variables used to
tell a TRUE/FALSE result, where none of those variables are ever used
in a comparison within the program itself.  For example, those truth
values may only be stored away in some database that is read by a
different program.  If the different program is C right now, you'll
define TRUE=1 and FALSE=0.  Next year, you may rewrite the different
program in some other language where TRUE is 0, and FALSE is 1, (maybe
because some contract requires a certain language for some parts of
the system), change the database structure, and you would then have to
redefine the constants in your C program.  Having a "#define ONE 0" in
my code is not something I would want. 

(This also has nothing to do with the argument about how good/bad it
is to have TRUE/FALSE defined because they can be misused by ignorant
programmers.  __Properly used__, a simple and easy to compile 0/1 set
of constants works.) 
-- 
Flint Pellett, Global Information Systems Technology, Inc.
1800 Woodfield Drive, Savoy, IL  61874     (217) 352-1165
uunet!gistdev!flint or flint@gistdev.gist.com

martin@mwtech.UUCP (Martin Weitzel) (09/04/90)

In article <585@quad.sialis.mn.org> dts@quad.sialis.mn.org (David T. Sandberg) writes:
>In article <664@csource.oz.au> david@csource.oz.au writes:
[and many many others wrote about their preference for #defining
TRUE and FALSE over simply using good ol' plain 1 and 0]

I quote the following only as an example:
>My two cents: I define FALSE as 0 and TRUE as 1 on a regular basis,
>but only use [... followed by about 10 more lines of rules when and
 when not to use TRUE and FALSE in statements]

People! Aren't you realizing what you are doing here?

K&R tried to make this very easy with C ... they LEFT OUT out a
"boolean" or "logical" datatype and gave *very simple* rules for
using int for that purpose. You need no more than these two
sentences to completly describe the behaviour:

	In every context where the further execution depends on
	a truth value of some expression, the value 0 is taken to
	mean FALSE and any other value is taken to mean TRUE.

	In any context where the execution of a builtin operator
	yields a truth value, this value is 0 for FALSE and 1 for
	TRUE.

But what are YOU doing: You clutter up this beautiful and easy to follow
mapping between int-s and truth values with new #defines or enum-s and
now of course you need additional rules, in which contexts your
augmentations may be safely used and where they are dangerous. In
the last an final result, whoever want's to use your TRUE and FALSE
must nevertheless understand the *whole* story, until he or she can
do it right all the time.

But isn't a claimed goal of some of you to make C easier to write by
defining TRUE and FALSE? No, it should only be easier to read?
So let me ask you: Why should anybody read your code if this person
hasn't sooner or later to modify this code or take at least part of
it as a template for own work? And how have you made sure that the
readers have grasped *your* strict rules when and when not to use
TRUE and FALSE and will apply it correctly?

Now, if you think it's such a bad idea to set a variable which has
only to reflect two states to the values 0 and 1 why don't you call
the formal constants somthing like SET, YES, ON, SUCCESS, ... (and
their counterparts CLEAR, NO, OFF, FAILURE, ...)?  Is it because
most of you (still) grew up with PASCAL?

And a final word to the ones who advocate "strong typing": You should
clearly vote for differently typed truth values (a la "new ...." in
ADA) - which of course are not supported by the C-compiler, but can
at least be done for "the eyes of the reader": If you are reluctant when
it comes to mixing (integer) numbers with truth values, you should
clearly vote for *differently named* constants for different sorts
of truth values. Take the following example:

	enum bool { FALSE, TRUE };
	bool fast_tty, can_scroll;
	.....
	/* if TTY is fast, we assume it can scroll */
	can_scroll = fast_tty;

Isn't this a bit like substituting apples for oranges? Shouldn't we rather
write:
	can_scroll = (fast_tty == TRUE) ? TRUE : FALSE;

If you strongly favour the latter for some reason, why not clarify it
further:

	enum { SLOW_TTY, FAST_TTY } tty_speed;
	enum { NO_SCROLL, CAN_SCROLL } scroll_mode;
	...
	scroll_mode = (tty_speed == FAST_TTY) ? CAN_SCROLL : NO_SCROLL;

Here we completly avoid TRUE and FALSE (of course we have to think hard
and invent other "good" names for our purpose), but we can later make
easly additions, eg.

	enum { NO_SCROLL, JUMP_SCROLL, SMOTH_SCROLL } scroll_mode;

And those of you who are paid based on how much lines of code you
write per month should also feel comfortable with this proposual :-)
-- 
Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83

dts@quad.sialis.mn.org (David T. Sandberg) (09/04/90)

In article <898@mwtech.UUCP> martin@mwtech.UUCP (Martin Weitzel) writes:
>In article <585@quad.sialis.mn.org> I wrote:
>>My two cents: I define FALSE as 0 and TRUE as 1 on a regular basis,
>>but only use [... followed by about 10 more lines of rules when and
> when not to use TRUE and FALSE in statements]

[...which was actually ten lines of explanation for just one rule,
partly because I do tend to be wordy, and partly in order to be certain
that I was not misunderstood and thereby avoid responses which border
on flamage criticizing understated elements of my rationale.  Silly me.]

>................................. how have you made sure that the
>readers have grasped *your* strict rules when and when not to use
>TRUE and FALSE and will apply it correctly?

Speaking for myself, I realize that this is a weak point in my own
TRUE-FALSE philosophy.  However, "my strict rules" can be quite
adequately summarized by a single comment next to the definition:

#define	TRUE	1		/* for assignments to flags ONLY! */
#define	FALSE	0		/* likewise */

Is this really that difficult to fathom?  Sure, the next programmer
could ignore it and use TRUE and FALSE in too general of a context
anyway, but he could also similarly abuse 90% of anyone's code - for
example, using local variables for multiple unrelated tasks in a
function.  So, how often do you bother to write comments like this?

	int c;		/* for the return value of getch() ONLY! */

Not often, I'd guess.  We have to depend on other programmers to
have some modicum of sense, after all, don't we?  If someone is
going to test the results of isalpha() or whatever against a macro
without even knowing what the macro is and is for, I am tempted to
say that they need to spend the extra ten minutes looking for the
problem so as not to repeat it in the future.  But saying it would
probably bring on more responses bordering on flamage, so I won't.  (-:

IMVHO, the whole point of having TRUE and FALSE available is to help
differentiate setting flags from arithmetic operations, and without
having to create a boolean data type.  Maybe my problem is that I
write structured(TM) code to a fault, commonly using flags to exit
loops or do error handling, rather than using goto or break.  When
the fabled next programmer comes along to read/support my code, I
expect something like "done = FALSE;" to be a lot more intuitive than
"done = 0;", since the latter could easily be arithmetic in nature,
whereas TRUE or FALSE should immediately imply that "done" is a flag.

So, either the next programmer can take a moment to learn what TRUE
and FALSE actually are, or he can go wading through code everytime he
sees 1 or 0 assigned to an int, to see if the result is being used
as a flag variable as opposed to an arithmetic one.  You can weigh
those tradeoffs as you see fit: the defines seem reasonably to me,
given my coding style.  (This will now undoubtedly degenerate into
a style war, in which I will not take part.)

>............................................... why don't you call
>the formal constants somthing like SET, YES, ON, SUCCESS, ... (and
>their counterparts CLEAR, NO, OFF, FAILURE, ...)?  Is it because
>most of you (still) grew up with PASCAL?

Not in my case at least.  And I have actually used descriptive
definitions like those you suggest on occasion.  But typically
my flag variables are named in such a way that TRUE and FALSE
"read" better than anything else. (Oh good; now maybe I'll be
accused of growing up with COBOL.)

-- 
 \\                                 \   David Sandberg, consultant   \\
 //         "Small hats!"           /   Richfield MN                 //
 \\                                 \   dts@quad.sialis.mn.org       \\

mtr@ukc.ac.uk (M.T.Russell) (09/04/90)

The reason for using TRUE and FALSE rather than 1 and 0 is simple: it
lets you say what you mean.  Someone once said that `GOSUB 9000' was
the most dismal statement in the whole of computing.  In my opinion
`boolvar = 1;' is in the same class.

To the people complaining about `if (x == TRUE)': YOU ONLY USE `TRUE' AND
`FALSE' FOR ASSIGNMENT AND PARAMETER PASSING.  It's a fairly simple rule.

I'd be interested to see some experiments with adding a `bool' type to a
C compiler (gcc?), with the following semantics:

	- bool has the same size and representation as int.

	- the comparison operators yield bool as the result type.

	- the `&&', `||' and `!' operators demand bool operands and
	  yield a bool result.  The ?: operator demands bool as its
	  first operand.  The only other operators that take bool
	  operands are `!=', `==' and `&' (address of).
	
	- `if', `do/while', `while' and `for' demand a bool expression
	  as the test.   Note that `if (ptr)' is still allowed by the
	  implicit rewrite to `if (ptr != 0)'.

	- assignment and comparison between bool and arithmetic types
	  is illegal without a cast, except for assignment to a bool
	  lvalue of an integral constant expression with the value 0 or 1.

This would provide some useful extra type checking, especially now that
we have function prototypes.  If `typedef int bool;' was allowed as a
special case, then code portability wouldn't be affected.

One weakness of this scheme is that it forces bool variables to take
the same space as an int.  I'm not sure whether adding `shortbool'
and `charbool' types (with appropriate conversion rules) would be worth
the additional complexity.  Programmers can always use casts.

BTW: these rules would reject `bool gotdigit = isdigit(c)', and rightly.

Mark Russell

peter@ficc.ferranti.com (Peter da Silva) (09/05/90)

In article <2341@cirrusl.UUCP> dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) writes:
>      i = isdigit(c);
>      ...
>      if (i == TRUE) ...

I would never do !if (anything == TRUE)! or !if (anything == FALSE)!. Not
only is it redundant, but it obscures the meaning of the code. If you have
a boolean-valued variable, it's clearer to say !if (anything)! or, for that
matter, !if (!anything)!.

The only think I use TRUE and FALSE for is:

	boolean = TRUE;
	return TRUE;
	function(..., TRUE, ...);
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.   'U`
peter@ferranti.com

userAKDU@mts.ucs.UAlberta.CA (Al Dunbar) (09/05/90)

In article <5398@harrier.ukc.ac.uk>, mtr@ukc.ac.uk (M.T.Russell) writes:
>...
 
>To the people complaining about `if (x == TRUE)': YOU ONLY USE `TRUE' AND
>`FALSE' FOR ASSIGNMENT AND PARAMETER PASSING.  It's a fairly simple rule.
>
 
Hear, hear!!!
 
I would hazard a guess at this point that perhaps the reason that
there is so much contention and misunderstanding here  is  simply
that  C  doesn't  have  a 'LOGICAL' (or boolean) type. In certain
contexts, an integral value is taken  by  the  compiler  to  mean
False if zero and True if non-zero. If you were forced to provide
an expression of boolean type, then the  compiler  would  quickly
straighten  everyone out, and 'if (x == TRUE)' would never appear
in a compiled program. The struggle to make it look like it has a
boolean type (such as the macros suggested recently, one of which
expanded to over 200K bytes!!!) are not doing much to add clarity
to  the  situation. Unfortunately, the solution is that we should
all learn the language a little better.
 
-------------------+-------------------------------------------
Alastair Dunbar    | Edmonton: a great place, but...
Edmonton, Alberta  | before Gretzky trade: "City of Champions"
CANADA             | after Gretzky trade: "City of Champignons"
-------------------+-------------------------------------------

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (09/05/90)

In article <5398@harrier.ukc.ac.uk> mtr@ukc.ac.uk (M.T.Russell) writes:
> To the people complaining about `if (x == TRUE)': YOU ONLY USE `TRUE' AND
> `FALSE' FOR ASSIGNMENT AND PARAMETER PASSING.  It's a fairly simple rule.

It is wise to take advantage of the language's syntax to remind the
programmer of this at every turn. If I were really desperate for this
type:

typedef struct { int truth; } truefalse;
#define set_true(b) ((void) ((b)->true = 1))
#define set_false(b) ((void) ((b)->true = 0))
#define is_true(b) ((b).true)

Usage: truefalse flagfoo; set_true(&flagfoo); if (is_true(flagfoo)) ...

Somehow in real programs I've never had trouble with declaring variables
flagthis, flagthat, flagtheotherthing. The ``flag'' alerts the reader.
Flags are multi-valued when I need to express different shades of truth.

---Dan

ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (09/05/90)

In article <5398@harrier.ukc.ac.uk>, mtr@ukc.ac.uk (M.T.Russell) writes:
> To the people complaining about `if (x == TRUE)': YOU ONLY USE `TRUE' AND
> `FALSE' FOR ASSIGNMENT AND PARAMETER PASSING.  It's a fairly simple rule.

All of _us_ reading this newsgroup may follow that rule, but as an
empirical observation a lot of people _don't_.  I have seen too many
Pascal programs where people wrote
	x: boolean; ... if x = TRUE then ...
(and in Pascal this _works_) to be sanguine about the programmers in
question learning better when they switch to C.  I have also seen this
kind of code in Algol programs, and if I were reading novice Ada programs
I'm sure I'd see it there.  I _have_ seen it in C code, and it was wrong.

Let's not forget the Lisp Lesson:  there is often something useful you
could return instead of an anonymous "true".  For example, if you are
looking for a character in a string, instead of returning TRUE (it is
there) or FALSE (it isn't) you could return a pointer to if it it's
there or NULL if it isn't.  If you program with that in mind, you really
don't _care_ much about TRUE/FALSE -vs- 1/0, because it's rare that you
have so little to say.
> 	- the `&&', `||' and `!' operators demand bool operands and
> 	  yield a bool result.  The ?: operator demands bool as its
> 	  first operand.  The only other operators that take bool
> 	  operands are `!=', `==' and `&' (address of).

Why should your proposed C variant be more restrictive than Pascal?
In Pascal FALSE < TRUE is allowed, meaningful, and true.
It is also allowed, meaningful, and true in Ada (LRM 3.5.3).

-- 
You can lie with statistics ... but not to a statistician.

mtr@ukc.ac.uk (M.T.Russell) (09/05/90)

In article <3686@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes:
>I have seen too many Pascal programs where people wrote
>	x: boolean; ... if x = TRUE then ...
> ... I _have_ seen it in C code, and it was wrong.

I don't want people who do that kind of thing hacking my code.
If they get something as simple as this wrong then what hope is
there of them getting anything else right?

>Why should your proposed C variant be more restrictive than Pascal?
>In Pascal FALSE < TRUE is allowed, meaningful, and true.

I can't see any use for this, but I don't have any violent objection
to it.

I'd make a couple of changes to my scheme on reflection: I'd disallow
assignment of 0 and 1 to bool variables, and make TRUE and FALSE keywords.
I'd also turn on a macro __BOOL__ to indicate that the extension was
there, so that applications could say:

	#ifndef __BOOL__
	typedef int bool;
	#define TRUE 1
	#define FALSE 0
	#endif

Mark

chip@tct.uucp (Chip Salzenberg) (09/05/90)

According to flint@gistdev.gist.com (Flint Pellett):
>Truth values may only be stored away in some database that is read by a
>different program.  If the different program is C right now, you'll
>define TRUE=1 and FALSE=0.  Next year, you may rewrite the different
>program in some other language where TRUE is 0, and FALSE is 1 ...

In such a case, the values stored in the database should best be named
DB_TRUE and DB_FALSE, with assignment such:

	db_boolean = boolean ? DB_TRUE : DB_FALSE;

External data representation is irrelevant to the TRUE/FALSE issue.
-- 
Chip Salzenberg at Teltronics/TCT     <chip@tct.uucp>, <uunet!pdn!tct!chip>

karl@haddock.ima.isc.com (Karl Heuer) (09/06/90)

[Lots of people have said:]
>Writing `if (b == TRUE)' is wrong.

No.  It's correct but silly (as is `if ((x < y) == TRUE)').  The flaw is in
writing `b = isdigit(ch)', because `isdigit()', despite the misleading name,
is *not* a Boolean function.  If this had been done right, the function would
be guaranteed to return the normalized truth value, namely 1, on success.
(Fixed in INTERACTIVE Unix, incidentally.  It's no less efficient under normal
usage, and less error-prone under abnormal usage.)


In article <3686@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes:
>Let's not forget the Lisp Lesson:  there is often something useful you
>could return instead of an anonymous "true".

Fine; functions that have that property can be declared with a type other than
"bool".  Functions that don't have any useful value to return on success can
and should return TRUE.  (fgets() was another mistake.)

>Why should your proposed C variant be more restrictive than Pascal?
>In Pascal FALSE < TRUE is allowed, meaningful, and true.

For the same reason that it's more restrictive than current C.  The relation
b1 < b2 isn't sufficiently useful to be worth supporting, IMHO (since it's
equivalent to !b1 && b2); and forbidding it may make it possible to catch real
mistakes.


In article <898@mwtech.UUCP> martin@mwtech.UUCP (Martin Weitzel) writes:
>K&R tried to make this very easy with C ... they LEFT OUT out a
>"boolean" or "logical" datatype and gave *very simple* rules for
>using int for that purpose.

Hey!  They could have made it *even simpler*, by making `int' and `float' the
same type, like in BASIC or APL!  (Sarcasm alert.)

Conceptually, C already has booleans: the operands of various control-flow
statements and operators; the results of relationals, etc.  The usual
description of the language is in terms of `int', but it would be equally
correct to say that `a < b' returns an object of type Boolean, and that
Booleans and integers are implicitly converted by the rules `i=(b?1:0)'
and `b=(i!=0)', and that there is no keyword for Boolean (and hence one may
not declare objects of that type, but must instead fall back on int).

>And how have you made sure that the readers have grasped *your* strict rules
>when and when not to use TRUE and FALSE and will apply it correctly?

It's not as if everyone is making up their own rules.  Not mixing Boolean and
integer data should simply an `obvious' rule, like not mixing pointers and
ints (even if you happen to be using a language that's sloppy about it--C in
the first case, BCPL in the second).

>[Why not use the names SET/CLEAR, YES/NO, ON/OFF, SUCCESS/FAILURE instead]?
>Is it because most of you (still) grew up with PASCAL?

Probably.  I use YES/NO myself, following Kernighan I believe, but I've
noticed it's a minority position.  If <bool.h> were standardized, I'd switch
to whatever it used.

>And a final word to the ones who advocate "strong typing": You should
>clearly vote for differently typed truth values: If you are reluctant when
>it comes to mixing (integer) numbers with truth values, you should
>clearly vote for *differently named* constants for different sorts
>of truth values.

This is true to some extent (and applies to other types as well as Booleans),
but (a) mixing apples and oranges is sometimes the right thing (how do you do
a matrix multiply if you've typedef'd `row_index' and `col_index'?), and (b)
at some point it just becomes too much work to declare a new type for an
object that has a small scope.  (Though if the compiler enforced the
type-mixing restriction, it might be worthwhile.)

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint

olu@sysauto.UUCP (Olumide O. Emuleomo) (09/06/90)

In article <2341@cirrusl.UUCP>, dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) writes:
> I was brash enough to suggest
> 
> But in fact my suggested definitions are much more useful than the
> common recommendation of defining TRUE and FALSE.
> 
> No matter how careful the original programmer is, sooner or later
> somebody will come along and, noticing that TRUE means true, will try
> to do something like:
> 
>      i = isdigit(c);
>      ...
>      if (i == TRUE) ...
> 
> Of course, defining ONE and ZERO is fairly silly.  But defining TRUE
> and FALSE is quite risky.  I'll take fairly silly over quite risky any
> day.
> --
> Rahul Dhesi <dhesi%cirrusl@oliveb.ATC.olivetti.com>
> UUCP:  oliveb!cirrusl!dhesi

TRUE and FALSE were never meant to be tested explicitly.

Good programming practise demands that they be used somewhat as follows

if( keyword_found(fname) )
{
	etc...
	etc... etc..
}


keyword_found(char *fname_param)
{
	switch(foo)  
	{
	 case FAILURE:
		etc...
		return(FALSE);
	 case SQLNOTFOUND:
		more etc..
		return(FALSE);
	 	etc...
	}

	return(TRUE);
}

Cheers

--olu@sysauto.UUCP

george@hls0.hls.oz (George Turczynski) (09/06/90)

In article <F4u9._?1@cs.psu.edu>, flee@guardian.cs.psu.edu (Felix Lee) writes:

> Personally, I use this set of macros:
> #define FALSE		0
> #define CNAND(a,b)	(!((a)&&(b)))
> #define CNOT(a)		CNAND(a,a)
> #define CXOR(a,b)	CNAND(CNAND(a,CNOT(b)),CNAND(b,CNOT(a)))
> #define CEQUIV(a,b)	CNOT(CXOR(a,b))
> #define COR(a,b)	CEQUIV(a,CNAND(CNOT(a),CXOR(a,b)))
> #define CAND(a,b)	CXOR(COR(a,b),CXOR(a,b))
> #define TRUE		COR(FALSE,CNOT(FALSE))
> #define ISTRUE(a)	CAND(TRUE,a)
> #define ISFALSE(a)	CNOT(ISTRUE(a))
> 
> These may unfortunately overrun some compiler or preprocessor limits
> (TRUE expands to an 853 character expression, and ISFALSE(x) expands
> to 203677 characters).  But they're otherwise quite portable, and I
> find the prefix style much more readable than C's cryptic infix
> expressions, especially when used in conjunction with a set of macros
> that provide LISP-ish control structures.

I don't think you'll find many compilers that are happy with those  
extremely inefficient macros.  Whether or not it compiles is one thing, 
but how long it takes is another ! 
 
I think that anything that expands to a 200,000 oharacter or so long 
expression is ridiculous, but that's my opinion :-)
 
Let me ask why you chose to use "!" and "&&" and ignored "||" ? Do
you not trust it or something ?  It is just as valid in C as "!" and
"&&" !
 
It is not clever to create such nonsensical macros.
 
Why not try these:
 
#define FALSE          0
#define CNOT(a)        (!(a)) 
#define CAND(a,b)      ((a)&&(b)) 
#define CNAND(a,b)     CNOT(CAND(a,b)) 
#define COR(a,b)       ((a)||(b)) 
#define CNOR(a,b)      CNOT(COR(a,b)) 
#define CXOR(a,b)      CNOR(CAND(a,b),CNOR(a,b)) 
#define CXNOR(a,b)     COR(CAND(a,b),CNOR(a,b)) 
#define CEQUIV(a,b)    CXNOR(a,b)    
#define TRUE           CNOT(FALSE) 
#define ISTRUE(a)      CAND(a,TRUE) 
#define ISFALSE(a)     CNOT(ISTRUE(a)) 
 
I too have used but one of each of "0", "!", "&&", and "||" as well.

Now, I can show you what these expand to, because they aren't ridiculously
long:

0
(!(a))
((a)&&(b))
(!(((a)&&(b))))
((a)||(b))
(!(((a)||(b))))
(!(((((a)&&(b)))||((!(((a)||(b))))))))
((((a)&&(b)))||((!(((a)||(b))))))
((((a)&&(b)))||((!(((a)||(b))))))
(!(0))
((a)&&((!(0))))
(!(((a)&&((!(0))))))

respectively.

Now, if anyone feels that they MUST use macros like these, use mine,
or even better, make your own up not defining them in terms of each
other, but in terms of "0", "!", "&&" and "||" (This will remove any
pairs of redundant parentheses).

Have a nice day...

-- 
| George P. J. Turczynski.          |---------------------------------------------------- 
| Computer Systems Engineer.        | ACSnet: george@highland.oz | I can't speak for the |
| Highland Logic Pty. Ltd.          | Phone: +61 48 683490       | company, I can barely |
| Suite 1, 348-354 Argyle St        | Fax:   +61 48 683474       | speak for myself...   |
| Moss Vale. NSW. Australia. 2577   |---------------------------------------------------- 

userAKDU@mts.ucs.UAlberta.CA (Al Dunbar) (09/06/90)

In article <23970:Sep505:16:2390@kramden.acf.nyu.edu>, brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>In article <5398@harrier.ukc.ac.uk> mtr@ukc.ac.uk (M.T.Russell) writes:
>> To the people complaining about `if (x == TRUE)': YOU ONLY USE `TRUE' AND
>> `FALSE' FOR ASSIGNMENT AND PARAMETER PASSING.  It's a fairly simple rule.
>
>Usage: truefalse flagfoo; set_true(&flagfoo); if (is_true(flagfoo)) ...
ARGH! the "is_true" is understood, and redundant ! 'if (flagfoo)'
means 'if flagfoo is true', in the same way that the following
two sentences mean (almost) exactly the same thing in English:
 
1) If it is raining you will get wet.
 
2) If it is true that it is raining you will get wet.
 
The is_true() macro is almost as useful as a macro you might
write to return the numeric value of its argument, i.e.:
 
a = value_of( b ) + value_of( c );
 
-------------------+-------------------------------------------
Al Dunbar          |
Edmonton, Alberta  |   this space for rent
CANADA             |
-------------------+-------------------------------------------

jar@ifi.uio.no (Jo Are Rosland) (09/06/90)

In article <3686@goanna.cs.rmit.oz.au>, ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes:
> Let's not forget the Lisp Lesson:  there is often something useful you
> could return instead of an anonymous "true".  For example, if you are
> looking for a character in a string, instead of returning TRUE (it is
> there) or FALSE (it isn't) you could return a pointer to if it it's
> there or NULL if it isn't.  If you program with that in mind, you really
> don't _care_ much about TRUE/FALSE -vs- 1/0, because it's rare that you
> have so little to say.

Exactly!  Some examples of this from Lisp, are:

	(or a b)
	(and a b)

which evaluate to either nil, or the value of a or b.

Why can't I do this in C?  The && and || operators are defined
to return either 0 or 1.  With the Lisp semantics I could write
code like:

	return f() || g();

instead of:

	a = f();
	if (a)
		return a;
	else
		return g();

This is useful eg. when f() and g() return pointers (maybe in
some sort of search, where we only want to call the second
function if the first one fails.)  And I even think the first
version reads better.

So why does && and || return 0 or 1?  What would break if they were
less restrictive?  Operators like <, >, ==, which are most often used
in conjunction with && and ||, return 0 or 1 anyway.

-- 
_____________________
 |/   Jo Are Rosland
 [)   joare@sdata.no

fmcwilli@oracle.oracle.com (Floyd McWilliams) (09/06/90)

In article <F4u9._?1@cs.psu.edu> flee@guardian.cs.psu.edu (Felix Lee) writes:
|Personally, I use this set of macros:
|#define FALSE		0
|#define CNAND(a,b)	(!((a)&&(b)))
|#define CNOT(a)		CNAND(a,a)
|#define CXOR(a,b)	CNAND(CNAND(a,CNOT(b)),CNAND(b,CNOT(a)))
|#define CEQUIV(a,b)	CNOT(CXOR(a,b))
|#define COR(a,b)	CEQUIV(a,CNAND(CNOT(a),CXOR(a,b)))
|#define CAND(a,b)	CXOR(COR(a,b),CXOR(a,b))
|#define TRUE		COR(FALSE,CNOT(FALSE))
|#define ISTRUE(a)	CAND(TRUE,a)
|#define ISFALSE(a)	CNOT(ISTRUE(a))

|These may unfortunately overrun some compiler or preprocessor limits
|(TRUE expands to an 853 character expression, and ISFALSE(x) expands
|to 203677 characters).  But they're otherwise quite portable, and I
|find the prefix style much more readable than C's cryptic infix
|expressions, especially when used in conjunction with a set of macros
|that provide LISP-ish control structures.

	Plus, the definitions are intuitively obvious!  One can only pity
the programmers who use such twisted constructs as

	if (!a)	/* If not a */
	if (a || b) /* If a or b */
	if (a && b) /* If a and b */

	and the unthinkable

	if (a) /* If a is true */

	p.s.  Felix, while it's true that TRUE is FALSE OR NOT FALSE, it also
happens to be NOT FALSE AND NOT FALSE.  So for _maximum_portability_, you
should have

#define TRUE CAND(COR(FALSE,CNOT(FALSE)),CAND(CNOT(FALSE),CNOT(FALSE)))

--
	Floyd McWilliams -- fmcwilli@oracle.com
"I don't mind anybody dropping out of anything, but it's the imposition on
 somebody else I don't like.  The moment you start dropping out and then
 begging off somebody else to help you, then it's no good." -- George Harrison

staff@cadlab.sublink.ORG (Alex Martelli) (09/07/90)

mtr@ukc.ac.uk (M.T.Russell) writes:

>In article <3686@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes:
	...omitted...
>>In Pascal FALSE < TRUE is allowed, meaningful, and true.

>I can't see any use for this, but I don't have any violent objection

An use is to implement the "MATERIAL IMPLICATION" operator of
propositional calculus; "a IMPLIES b" can be written "a <= b"
under Pascal's ordering (yup, as another poster points out, it
can also be written "b OR NOT a", but then why have an AND 
operator at all, since it "a AND b" can be easily rewritten
"NOT (NOT a OR NOT b)"...?-).

-- 
Alex Martelli - CAD.LAB s.p.a., v. Stalingrado 45, Bologna, Italia
Email: (work:) staff@cadlab.sublink.org, (home:) alex@am.sublink.org
Phone: (work:) ++39 (51) 371099, (home:) ++39 (51) 250434; 
Fax: ++39 (51) 366964 (work only; any time of day or night).

mcdaniel@adi.com (Tim McDaniel) (09/07/90)

In article <F4u9._?1@cs.psu.edu> flee@guardian.cs.psu.edu (Felix Lee) writes:
> Personally, I use this set of macros:
>    #define FALSE        0
>    #define CNAND(a,b)   (!((a)&&(b)))
>    #define CNOT(a)      CNAND(a,a)
>    #define CXOR(a,b)    CNAND(CNAND(a,CNOT(b)),CNAND(b,CNOT(a)))
> ...
> These may unfortunately overrun some compiler or preprocessor limits
> (TRUE expands to an 853 character expression, and ISFALSE(x) expands
> to 203677 characters).

I called each macro once and printed the resulting lengths (assuming a
character-based preprocessor).  It took about 90 CPU seconds to
compile on a Sun 3/60 with a local hard disk.

   Macro call   Length          Macro call      Length
   
   FALSE        1               COR(x,y)        637   
   CNAND(x,y)   13              CAND(x,y)       2149  
   CNOT(x)      13              TRUE            853           
   CXOR(x,y)    61              ISTRUE(x)       101833
   CEQUIV(x,y)  133             ISFALSE(x)      203677        

ISTRUE generates so many characters because it uses CAND, which passes
its first argument (here, TRUE) to both COR and CXOR; COR passes three
copies to CEQUIV, CNOT, and CXOR, respectively; et cetera.

> especially when used in conjunction with a set of macros that
> provide LISP-ish control structures.

I haven't found a good way to do LAMBDA -- any suggestions?  With
'm4', of course, it's trivial.

I rather like the way I did CONS.  I didn't want the overhead of
checking for free space and allocating more on every call.  Basically,
it increments the free-store pointer and just dereferences it.  If
it's a bad pointer now, a signal handler does an "sbrk" to get a lot
more space, and it restarts the instruction that failed.  And it's so
portable -- at least, it worked on every VAX that I tried it on.

Have I mentioned dereferencing NIL yet, to get 0?

By the way, would anyone like a copy of the shell I wrote in this
LISPish C?  I call it "The Still-Bourne Shell".
--
Tim McDaniel                 Applied Dynamics Int'l.; Ann Arbor, Michigan, USA
Work phone: +313 973 1300                            Home phone: +313 677 4386
Internet: mcdaniel@adi.com                UUCP: {uunet,sharkey}!amara!mcdaniel

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (09/07/90)

In article <1308@mts.ucs.UAlberta.CA> userAKDU@mts.ucs.UAlberta.CA (Al Dunbar) writes:
> In article <23970:Sep505:16:2390@kramden.acf.nyu.edu>, brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
> > In article <5398@harrier.ukc.ac.uk> mtr@ukc.ac.uk (M.T.Russell) writes:
> > > To the people complaining about `if (x == TRUE)': YOU ONLY USE `TRUE' AND
> > > `FALSE' FOR ASSIGNMENT AND PARAMETER PASSING.  It's a fairly simple rule.
    [ I point out how you can enforce this with syntax, if you're desperate ]

> ARGH! the "is_true" is understood, and redundant !

Even if you were right, that would be irrelevant ! The point of this
discussion is to please Pascal programmers. Once again, the following
should satisfy them:

  typedef struct { int truth; } truefalse;
  #define set_true(b) ((void) ((b)->true = 1))
  #define set_false(b) ((void) ((b)->true = 0))
  #define is_true(b) ((b).true)
  
  Usage: truefalse flagfoo; set_true(&flagfoo); if (is_true(flagfoo)) ...

Notice that if (flagfoo) is illegal, and there is no possible problem
along the lines of if (flagfoo == TRUE). Unless I'm mistaken, this is
what the Pascalites are looking for. (Isn't it?)

---Dan

jimmy@tybalt.caltech.edu (Jimmy Hu) (09/07/90)

In article <5409@harrier.ukc.ac.uk> mtr@ukc.ac.uk (M.T.Russell) writes:
>
>I'd make a couple of changes to my scheme on reflection: I'd disallow
>assignment of 0 and 1 to bool variables, and make TRUE and FALSE keywords.
>I'd also turn on a macro __BOOL__ to indicate that the extension was
>there, so that applications could say:
>
>	#ifndef __BOOL__
>	typedef int bool;
>	#define TRUE 1
>	#define FALSE 0
>	#endif

There only purposes for a boolean type in C are for "increased
readability" and "stronger type-checking." But for me, personally,
the reason I use C instead of say, Pascal, is that I don't want all
these restrictions. I don't want to hide the fact that the "booleans"
I use are actually ints. I LIKE the fact that C's "booleans" are ints,
and I use that fact when I write something like:

d = (a==b)*c;         /* Just a contrived example to set d to 0 or c */

I like the fact that all nonzero values are considered true. For
instance, when I have an int in which I may or may not have set
certain bits, and I want to know if I have set any, I can just
write "if (flags)" and not "if (flags != 0)."  Or if I want to check
a certain bit, I can write "if (flags & 0x0800)" and not
"if ((flags & 0x0800) != 0)."

Now I have no objection to people who use TRUE and FALSE for better
readability as long as they know what they're doing. And if they want
to construct a boolean type with bool.h, that's also fine with me. But
as for the idea of making a standard boolean type for C, I'd have to
say that this is going a bit too far, since it would make life difficult
to the many programmers who actually make good use of ints as booleans.
Since most languages compile booleans to ints anyways, why not use that
extra space for your own purposes?

About the macros that put out a 200000+ character definition, I think
that this is just plain silly. Most of those definitions could have been
shortened by defining them on C's operators instead of on each other. Why
make the compiler spend minutes deciphering "ISFALSE(x)" and substituting
a monstrously convoluted synonym for (!(x))? I mean, this is C, so use it
to your full advantage, right? You don't have to use the more restrictive
Pascal-like or the more verbose Lisp-like constructs! I think other C
programmers looking at your code will understand what you mean even when
you use obscure things like "if (x)" instead of "if ISTRUE(x)." :-)

--
----------------------------------------------------------------------
Jimmy Hu                                      jimmy@tybalt.caltech.edu
----------------------------------------------------------------------

stephen@estragon.uchicago.edu (Stephen P Spackman) (09/07/90)

To pick up on a couple of comments:

In article <1990Sep6.113259.2109@ifi.uio.no> jar@ifi.uio.no (Jo Are Rosland) writes:

   Why can't I do this in C?  The && and || operators are defined
   to return either 0 or 1.  With the Lisp semantics I could write
   code like:

	   return f() || g();

   instead of:

	   a = f();
	   if (a)
		   return a;
	   else
		   return g();

   This is useful eg. when f() and g() return pointers (maybe in
   some sort of search, where we only want to call the second
   function if the first one fails.)  And I even think the first
   version reads better.

The single most important case is, of course, when f() and g() return
functions. You could code all of that ecchy high-level
strategy-finding code in this style:

	return (f() || g())(x);

And if THAT ain't clarity, I don't know what is.

In article <1990Sep6.113259.2109@ifi.uio.no> jar@ifi.uio.no (Jo Are Rosland) writes:

   The is_true() macro is almost as useful as a macro you might
   write to return the numeric value of its argument, i.e.:

   a = value_of( b ) + value_of( c );

I'm in favour, though I'd like to see a prefix operator for this.
There damn well ought to be an operator for extracting values from
variables, so people don't confuse them with constants.

And to encourage them to USE constants.

(And it's been done in real languages, honest).

stephen p spackman  stephen@estragon.uchicago.edu  312.702.3982

simons@tetrauk.UUCP (Simon Shaw) (09/07/90)

In article <926@hls0.hls.oz> george@hls0.hls.oz (George Turczynski) writes:
>In article <F4u9._?1@cs.psu.edu>, flee@guardian.cs.psu.edu (Felix Lee) writes:
>
>> Personally, I use this set of macros:
>> #define CNAND(a,b)	(!((a)&&(b)))
>> #define CNOT(a)		CNAND(a,a)
>> #define CXOR(a,b)	CNAND(CNAND(a,CNOT(b)),CNAND(b,CNOT(a)))
> 
>Why not try these:
> 
>#define CNOT(a)        (!(a)) 
>#define CAND(a,b)      ((a)&&(b)) 
>#define COR(a,b)       ((a)||(b)) 
>#define CNOR(a,b)      CNOT(COR(a,b)) 
>#define CXOR(a,b)      CNOR(CAND(a,b),CNOR(a,b)) 

If because the value returned by an expression of the form (a == b)
is _defined_ to be 0 or 1, we are defining TRUE as 1 and ZERO as 0
(no contention yet, I hope), then the worst of these expansions, 
XOR, should be contracted by the use of the bitwise XOR.

#define	CXOR(a,b) ((a)^(b))

with this assumption (TRUE==1, FALSE==0), are there any circumstances 
where the use of the bitwise operator would be unsafe ?

IMHO, the compounds NOR and NAND, while much more useful if constructing 
electronic circuitry, are considerably less clear in code (Not to mention
XNOR, which even now takes me a few seconds to work out).  Lets not
forget the poor sods who've got to maintain this code !

Anyone disagree ?

-- 
Simon Shaw ; simons@tetrauk.uucp

chip@tct.uucp (Chip Salzenberg) (09/07/90)

According to joare@sdata.no:
>	return f() || g();

Perl also has the LISP meaning for this operation.

This C equivalent is too verbose:

>	a = f();
>	if (a)
>		return a;
>	else
>		return g();

Try instead:

        return (a = f()) ? a : g();

Note that GNU CC has a ?: operator where the second operand defaults
to the value of the first operand.  So with GNU CC, you can write:

        return f() ?: g();

Followups to alt.lang.cfutures.
-- 
Chip Salzenberg at Teltronics/TCT     <chip@tct.uucp>, <uunet!pdn!tct!chip>

jcl@bdrc.bd.com (John C. Lusth) (09/07/90)

Rahul Dhesi writes:
<When I find somebody who really, really, really wants to define TRUE
<and FALSE, even somebody who uses them for assignment only, I recommend
<the following defines instead:
<
<     #define ZERO   0
<     #define ONE    1
<
<These are so much more clear than TRUE and FALSE, and if you use
<them in a test, you know exactly what you're testing!

Concerning the various disparaging remarks about the stupidity
of the above defines:

Jeez, guys, don't you know sarcasm when you see it?  Defining
TRUE and FALSE in C is just about as stupid as defining ZERO and ONE.

john
-- 
John C. Lusth, Becton Dickinson Research Center, RTP, NC, jcl@bdrc.bd.com

ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (09/09/90)

>In article <F4u9._?1@cs.psu.edu>, flee@guardian.cs.psu.edu (Felix Lee) writes:
> Personally, I use this set of macros:
> #define CNAND(a,b)	(!((a)&&(b)))

Surely this was a joke?

In article <728@tetrauk.UUCP>, simons@tetrauk.UUCP (Simon Shaw) writes:
> IMHO, the compounds NOR and NAND, while much more useful if constructing 
> electronic circuitry, are considerably less clear in code (Not to mention
> XNOR, which even now takes me a few seconds to work out).

What's in a name?  XNOR(a,b) is just !!(a) == !!(b), true when a and b
have the same "truth value", false when they differ.  It's available in
Fortran under the name .EQV., in Algol 60 under the name %equiv, and in
Pascal and Ada under the name '='.  Rename XNOR() to BoolEqual() and it
is pretty easy to figure out.
-- 
Psychiatry is not about cure.  Psychiatry is about power.

george@hls0.hls.oz (George Turczynski) (09/11/90)

In article <728@tetrauk.UUCP>, simons@tetrauk.UUCP (Simon Shaw) writes:
> In article <926@hls0.hls.oz> george@hls0.hls.oz (George Turczynski) writes:
> >Why not try these:
> > 
> >#define CNOT(a)        (!(a)) 
> >#define CAND(a,b)      ((a)&&(b)) 
> >#define COR(a,b)       ((a)||(b)) 
> >#define CNOR(a,b)      CNOT(COR(a,b)) 
> >#define CXOR(a,b)      CNOR(CAND(a,b),CNOR(a,b)) 
> 
> If because the value returned by an expression of the form (a == b)
> is _defined_ to be 0 or 1, we are defining TRUE as 1 and ZERO as 0
> (no contention yet, I hope), then the worst of these expansions, 
> XOR, should be contracted by the use of the bitwise XOR.
> 
> #define	CXOR(a,b) ((a)^(b))

No, I think not.  These macros all return a result that is TRUE or FALSE.
The bitwise XOR operator will not always produce the result TRUE or FALSE.
These macros are not performing bitwise arithmetic, but logical arithmetic.

> with this assumption (TRUE==1, FALSE==0), are there any circumstances 
> where the use of the bitwise operator would be unsafe ?

In this case, yes.  If someone were to say:-

	if( CXOR(a,b) == TRUE )

they would in most cases be in trouble, if the XOR operator was used.  Now,
you and I both know that few people would construct it like that, but that
is beside the point, these macros ALWAYS result in TRUE or FALSE.

> IMHO, the compounds NOR and NAND, while much more useful if constructing 
> electronic circuitry, are considerably less clear in code (Not to mention
> XNOR, which even now takes me a few seconds to work out).  Lets not
> forget the poor sods who've got to maintain this code !
> 
> Anyone disagree ?

Don't think for one second that I would entertain the idea of using these macros !
Felix Lee posted his set, some of which expanded to 200,000++ characters.
Thinking this was ridiculous, and that I might save some people wasting too
much of their time, I posted the same (but improved) macro set, that didn't
waste so much space.

I agree, don't waste your time with the above macros.  (But Felix Lee could
at least use the sensible ones, not the 200,000++ char ones :-})

-- 
| George P. J. Turczynski.          |---------------------------------------------------- 
| Computer Systems Engineer.        | ACSnet: george@highland.oz | I can't speak for the |
| Highland Logic Pty. Ltd.          | Phone: +61 48 683490       | company, I can barely |
| Suite 1, 348-354 Argyle St        | Fax:   +61 48 683474       | speak for myself...   |
| Moss Vale. NSW. Australia. 2577   |---------------------------------------------------- 

mcdaniel@adi.com (Tim McDaniel) (09/11/90)

Ye gods, folks, get a clue!

george@hls0.hls.oz (George Turczynski) writes:

   Don't think for one second that I would entertain the idea of using
   these macros!  Felix Lee posted his set, some of which expanded to
   200,000++ characters.  Thinking this was ridiculous, and that I
   might save some people wasting too much of their time, I posted the
   same (but improved) macro set, that didn't waste so much space.

Felix Lee was indeed being ridiculous -- deliberately.  It is called
"satire", a subclass of the class "joke".  Specifically, he was
"making fun" of the whole TRUE/FALSE definition topic.  Trying to
"optimize" those macros was itself a complete waste of time.

My own contribution was
>
> I rather like the way I did CONS.  I didn't want the overhead of
> checking for free space and allocating more on every call.  Basically,
> it increments the free-store pointer and just dereferences it.  If
> it's a bad pointer now, a signal handler does an "sbrk" to get a lot
> more space, and it restarts the instruction that failed.  And it's so
> portable -- at least, it worked on every VAX that I tried it on.
>
> Have I mentioned dereferencing NIL yet, to get 0?
>
> By the way, would anyone like a copy of the shell I wrote in this
> LISPish C?  I call it "The Still-Bourne Shell".

NOTE: THESE WERE ALSO "JOKES", as may be inferred from the
"portability == VAX" line.  Among other things, signal handlers on
some machines cannot or do not restart the instruction that failed.
Also, "(char *) 0" can be dereferenced in a *few* operating systems to
get '\0', but on most architectures, it causes a fatal error or
fetches garbage.  (See the "Frequently-Asked Questions" list.)

The original Bourne shell (called /bin/sh on most machines) was
written in pseudo-Algolish C, and used the "sbrk" kludge to do memory
allocation.  It was a maintenance nightmare and ridiculously
unportable, and basically had to be rewritten.
--
Tim McDaniel                 Applied Dynamics Int'l.; Ann Arbor, Michigan, USA
Work phone: +313 973 1300                            Home phone: +313 677 4386
Internet: mcdaniel@adi.com                UUCP: {uunet,sharkey}!amara!mcdaniel

amull@Morgan.COM (Andrew P. Mullhaupt) (09/13/90)

In article <MCDANIEL.90Sep11124417@dolphin.adi.com>, mcdaniel@adi.com (Tim McDaniel) writes:
| Ye gods, folks, get a clue!
| 
| george@hls0.hls.oz (George Turczynski) writes:
| 
|    Don't think for one second that I would entertain the idea of using
|    these macros!  Felix Lee posted his set, some of which expanded to
|    200,000++ characters.  Thinking this was ridiculous, and that I
|    might save some people wasting too much of their time, I posted the
|    same (but improved) macro set, that didn't waste so much space.
| 
| Felix Lee was indeed being ridiculous -- deliberately.  It is called
| "satire", a subclass of the class "joke".  Specifically, he was
| "making fun" of the whole TRUE/FALSE definition topic.  Trying to
| "optimize" those macros was itself a complete waste of time.

I don't think so. I think I could get them to expand to a Meg if I
thought about it...one of the funniest guys I ever knew was Steve
Pomerance, who had perfected the technique (which I still call
Pomerancing) of pretending to completely miss the point of your joke
until after you had explained it at least three different ways.
You should meet him.

Later,
Andrew Mullhaupt

| NOTE: THESE WERE ALSO "JOKES"

You said it.

george@hls0.hls.oz (George Turczynski) (09/17/90)

In article <MCDANIEL.90Sep11124417@dolphin.adi.com>, mcdaniel@adi.com (Tim McDaniel) writes:
> Ye gods, folks, get a clue!
  ...
> 
> Felix Lee was indeed being ridiculous -- deliberately.  It is called
> "satire", a subclass of the class "joke".  Specifically, he was
> "making fun" of the whole TRUE/FALSE definition topic.  Trying to
> "optimize" those macros was itself a complete waste of time.
  ...

With all the nonsensical things that people post (some of which ARE in earnest)
one just can't tell what is foolishness and what is satire.  Some of it can't
be very good satire, else certain people wouldn't mistake it for foolishness :-)

If all such articles were taken as `satire', many people would go on blindly
using their sometimes questionable ideas.  Where would that leave them ?

I will, in future, be on the lookout for such satirical articles :-)

-- 
| George P. J. Turczynski.          |---------------------------------------------------- 
| Computer Systems Engineer.        | ACSnet: george@highland.oz | I can't speak for the |
| Highland Logic Pty. Ltd.          | Phone: +61 48 683490       | company, I can barely |
| Suite 1, 348-354 Argyle St        | Fax:   +61 48 683474       | speak for myself...   |
| Moss Vale. NSW. Australia. 2577   |---------------------------------------------------- 

mautner@odin.ucsd.edu (Craig Mautner) (09/25/90)

The author of this does not have access to the news groups.
He asked me to post this and see what comments it generates.
Any correspondence should be sent to him at the internet address
included in the header.

-Craig Mautner

//////////////////// Begin Included Message ////////////////////////


              Seven Original Sins of K&R
                 by Philip J. Erdelsky
                Compuserve: 75746,3411
          Internet: 75746.3411@compuserve.com
                  September 22, 1990

The creation of C approximately two decades ago was a 
wondrous event, even if it did not seem so at the time.  
Like all human creations, C was imperfect.  I have 
identified seven Original Sins--minor flaws in C for 
which K&R will eventually have to answer, in this world 
or the next.  I call them original sins because they were 
present when C originated, not because K&R were the 
first to commit them.  Some of these sins have been 
purged from later versions of C, but others remain with 
us.

I am not the first to decry these sins, nor will I be 
the last.  I am merely another in a long series of 
prophets crying in the wilderness.

                           I

The First Original Sin was pitifully weak typing.  
There is no Boolean type in C, so generations of 
programmers have erroneously written something like "if 
(x=5)" instead of "if (x==5)", only to wonder why x 
always seems to be 5, regardless of what has gone 
before.  The "char" type was not specified as either 
signed or unsigned.  This sin has probably wasted more 
CPU time than any other, as savvy programmers learn to 
put a defensive "&0xFF" after every "char" expression 
that needs to be unsigned.  The default type for 
functions should have been "void", not "int", but there 
was originally no "void" type.

Modern compilers have provided partial redemption from 
this sin, usually by issuing warning messages when the 
program appears to be tainted.  But these warnings are 
often false alarms and go unheeded.  There is still no 
Boolean type, and "char" may be either signed or 
unsigned.  Even the new enumeration types are merely 
integers in disguise, just as willing to be mixed as 
matched.

                          II

The Second Original Sin was the failure to make "NULL" 
a keyword.  Beginning C programmers wonder why you have 
to "#include <stdio.h>" in a program that doesn't use 
standard I/O.  Some compilers don't even object when 
you assign an integer constant to a pointer without a 
typecast, especially when the constant happens to be 
zero.  Don't blame the compiler.  The poor thing can't 
tell the difference between a zero integer constant and 
"NULL".

Redemption from this sin is on its way.  Modern 
compilers define "NULL" as "(void *) 0", so there's at 
least some hope of distinguishing it from a plain old 
zero.

                          III

The Third Original Sin was the use of the keyword 
"static" to mark a function or variable as local to 
particular source file.  This is really a trinity of 
sins.  The word "static" doesn't mean local.  It 
conflicts with the other use of the word "static"--to 
mark a variable inside a function as one that actually 
is static, in an accepted meaning of the word.  
Finally, even if the word "local" had been used 
instead, it would have been marking the wrong thing.  
The word "public", or some similar word, should have 
been used to mark the few functions and variables that 
must be made available to the code in other files.  
Other functions and variables should have been local by 
default.  That's how it's done in assembly language and 
other high-level languages, and the reason for it is 
obvious.

From this sin, however, no redemption is in sight.

                          IV

The Fourth Original Sin is the mandatory use of the 
"break" keyword to terminate a "case" clause in a 
"switch" statement.  Omitting it is natural for 
beginning programmers, and sometimes even for 
experienced programmers who have been dabbling in more 
tightly structured languages.  Of course, this causes 
control to fall through to the next case, which is 
occasionally useful but nearly always a mistake, like a 
double exposure in photography.  But the evil goes even 
further.  Often, the "switch" statement is enclosed in 
a "for" or "while" loop.  You want to finish up a 
"case" clause by breaking out of the loop?  You can't 
do it in C, not without breaking out of the "switch" 
statement first!

The solution, not likely to be adopted even in C+++, 
would be to have the compiler put an implicit "break" 
at the end of every "case" clause, and reserve the 
"break" keyword for breaking out of loops, the way God 
intended.

                           V

The Fifth Original Sin was the way functions are 
defined.  The entire parameter list has to be written 
twice.  That's something no programmer should have to 
do unless it's absolutely necessary.  And to compound 
the evil, an untyped parameter defaults to type "int".  
Most programmers have written something like 
"strcmp(s,t)", forgetting the declaration "char 
*s,*t;".  What you wind up with in most cases is, not a 
function that fails, but something worse--a function 
that works as long as pointers and integers are the 
same size, and then fails when you try to port it.

Fortunately, ANSI C permits prototype definitions, but 
the old way is still permitted, at least during a 
transitional period.  Let's hope the transition is 
brief.

                          VI

The Sixth Original Sin was the way conflicts among the 
names of members of different structures were neither 
forbidden nor resolved.  The original K&R said that 
different structures could have members with identical 
names as long as they had identical offsets.  The way 
early compilers implemented this dictum varied.  Some 
compilers would check to see that the offsets were 
indeed identical.  Others simply generated erroneous 
code when they weren't.  Most programmers took the 
safest course by including the structure name--usually 
abbreviated--in every member name.

Modern compilers have atoned for this sin completely by 
keeping a separate member list for each structure type.  
This resolves the conflicts, but a reminder of past 
iniquities persists in the awkward names of structure 
members in UNIX source code and other old C scriptures.

                          VII

The Seventh Original Sin was the eight-character limit 
on distinguishable names, or even fewer than eight for 
externally defined names.  Of course, some such 
limitation was required for efficient implementation, 
but eight characters are not enough.  C was much better 
than Fortran, which allowed only six, but there are 
many pairs of English words with distinct meanings 
whose first eight letters are identical.  The minimum 
number depends on the language, but for English about 
20 should be sufficient.  German programmers need more.

Most modern compilers do have a reasonable limit, but 
some compiler developers have apparently forgotten that 
virtue lies in moderation.  One compiler allows at 
least several hundred characters, maybe more.  That's 
too long.  Compilers are supposed to compile, not test 
the limits of computability by allowing single labels 
to occupy practically the entire computer memory (and 
disk swap area).  An unprintable name--one that won't 
fit on a single line--should also be uncompilable.

                       Epilogue

None of these sins is inconsistent with the philosophy 
of C.  We needn't embrace heresies like Pascal, Modula 
2 or Ada.  But we must abandon the false god of 100% 
upward compatibility.  We must tear down the old temple 
to build a new one.  Then, and only then, will our 
redemption be at hand.

                         Note

This jeremiad is not copyrighted.  You are welcome to 
copy it and pass it on.  I only ask you to leave my 
name and account number on it.  Let me take the 
credit--and the heat.

//////////////////// End Included Message ////////////////////////
-- 
--------------------------------------------------------------------
Craig D. Mautner		UCSD
mautner@cs.ucsd.edu		Dept of CSE, C-014
(619) 534-4526			La Jolla, Ca. 92093

ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (09/26/90)

In article <12777@sdcc6.ucsd.edu>, mautner@odin.ucsd.edu (Craig Mautner) writes:
[1.  "Weak typing" was the phrase used, but actually
;    no "bool" type, and
;    char neither signed nor unsigned
were the real complaints.]

In the beginning there was CPL, an Algolish language with lots of goodies
including types.  CPL begat BCPL, which was the nearest thing there was to
a portable "implementation language" for years.  However, BCPL had one type:
"machine word", which had to serve for integer, float, and (word) address.
BCPL begat B, and B begat C, which broke with years of BCPL/B tradition by
adding types (it took a couple of revisions, but they're there).

'char' was neither signed nor unsigned because the machines of the time
didn't support both well; on a PDP-11 unsigned char was much more costly
than signed char, while on an IBM/360 signed char was much more costly
than signed char.  The one thing you were guaranteed was that any character
in the machine's usual alphabet could be represented in a 'char'.  This is
not a case of weak typing:  this implementation freedom in the representation
of characters was excellent engineering.  That there was no _separate_ type
for "8 bit integer", _that_ is the weak point.  But there weren't originally
any unsigned integers either.  (In UNIX V6 it was still common to use
pointer arithmetic to get unsigned integer arithmetic.)

It may sound as though I am nit-picking, but there's really no point in
raving on about the faults of a programming language unless you get it
quite clear what the faults really are.

Something which has long puzzled me is why so much of BCPL was retained
in C, yet MANIFEST was not.  In BCPL you could say
	MANIFEST $( I = 1, J = 2, K = 3 $)
which corresponds to ANSI C
	const int i = 1, j = 2, k = 3;
and as in ANSI C the "initial values" could be expressions.  Oh well,
what was that about repeating history?

[2.  NULL not a keyword]

> Beginning C programmers wonder why you have to "#include <stdio.h>"
> in a program that doesn't use standard I/O.

Any beginning C programmer who wonders any such thing has been
taught shockingly badly.  You *don't* have to include stdio.h.
In ANSI C, NULL is defined in at least three places:
	stddef.h	NULL, offsetof, ptrdiff_t, size_t, wchar_t
	stdlib.h	NULL, EXIT_SUCCESS, EXIT_FAILURE, lots of fns
	stdio.h		NULL, FILE, fopen, ...
In pre-ANSI C, there's nothing to stop you #define'ing NULL yourself.
I was in the habit of using explicit casts, (char*)0 and the like.

> Redemption from this sin is on its way.  Modern 
> compilers define "NULL" as "(void *) 0"

No.  ANSI-compliant compilers have *permission* to define NULL this
way, but all three of 0, 0L, and (void*)0 are allowed.  _Some_ compilers
will define NULL to be (void*)0, but other compiler writers will have
compassion on the idiots who wrote "char x = NULL;" and not break their
programs.

[3.  static]

This could be argued several ways.  I have long had in my personal
header file
	#define public
	#define private static
"static" is not such a big deal.  Remember, the norm for good C style
is to have a very small number of functions in a file, which means that
'static' functions are expected to be rare.

If you knew how BCPL used to tie things together, you would agree that
the way C does it is a _big_ improvement.  (Would you believe an
explicit "global vector" with externals identified by number?)

[4.  break]

There are two separate and distinct issues here, and it really doesn't
help to confuse them.

    1.  "case xxx:" in C is just a label, and no more contains a jump
	than any other kind of label.  So you can "fall through" into
	the next case.

    2.  The way you say "get out of the switch () statement" is the
	same as the way you say "get out of a while ()", so it is
	pointlessly hard to have a switch case that exits a loop.

BCPL had property 1, but not property 2.  In BCPL, the way that you
said "get out of the switch ()" was ENDCASE, while the way that you
said "get out of the loop" was BREAK.  It is a mystery to me why B
or C ever changed this.  But it is important to be clear about the
fact that the two properties are quite independent.

[5.  function definitions]

> The Fifth Original Sin was the way functions are defined.
> The entire parameter list has to be written twice.

This meant that one could easily _add_ parameter type information
to existing V5 or V6 code.  It also imitated Algol 60 and Fortran.
It wasn't by any means an innovation.  I actually rather like the
Algol/Fortran/classic-C style of function header, because it is
very easy to indent consistently (unlike the Algol 68/Pascal/Ada
approach), and is a splendid opportunity to place the usual
explanatory comment:
	type foo(x, y, z)
	    xtype x;	/* say what x is all about */
	    ytype y;	/* say what y is all about */
	    ztype z;	/* say what z is all about */

> Most programmers have written something like 
> "strcmp(s,t)", forgetting the declaration "char 
> *s,*t;".  What you wind up with in most cases is, not a 
> function that fails, but something worse--a function 
> that works as long as pointers and integers are the 
> same size, and then fails when you try to port it.

I don't understand this.  If the body of the function refers to
*s or *t (and it is hard to imagine an implementation of strcmp
that didn't) the compiler will catch it.  Nothing about the
relative sizes of pointers and integers is involved.  Other parts
of the program (in classic C) don't know the argument types _anyway_,
so we're only concerned here with the effect on the function definition.
I can imagine problems if int and long aren't the same size, but how do
you get something where pointer/int is a likely confusion?

[7.  eight-character names]

> The Seventh Original Sin was the eight-character limit 
> on distinguishable names, or even fewer than eight for 
> externally defined names.  Of course, some such 
> limitation was required for efficient implementation, ...
> for English about 20 [characters] should be sufficient.

This simply isn't true.  No limitation whatsoever is necessary for
efficient implementation.  20 is nowhere *near* enough for English,
and 31 is barely adequate.

Recall that from quite early days, C has been used on other platforms
than UNIX.  Name length restrictions are a regrettable fact of life
with other people's linkers.  Blame the linkers, not the language.
I can't say that I was impressed by the UNIX V7 linker's restrictions,
but do bear in mind that it had to work in an address space of 64kb
*total*.  It was a big improvement on the IBM 1130's 5-character limit!

The ANSI C standard imposes *no* limit on the number of characters that
a C system *may* consider significant.  A compiler _may_ look at only
the first 31 characters, but it _may_ regard them all as significant.
A portable program must ensure that external identifiers are unique in
the first six characters (after case folding, too), but that's not a
sin in C, it's a fact of life about other people's linkers.  On a modern
UNIX system, all the characters are significant.

> But we must abandon the false god of 100% upward compatibility.

C is a language with a history.  To adapt a metaphor from S.J.Gould,
think of it as a panda, but as a panda that's all thumbs (:-).  There
never has been a goal (let alone a god) of 100% upward compatibility.
But the goal of 95% upwards compatibility was vital:  if the standard
had been too radically different, it wouldn't have been usable as a
standard for *C*.

-- 
Fixed in the next release.

mcdaniel@adi.com (Tim McDaniel) (09/26/90)

In an otherwise excellent article, ok@goanna.cs.rmit.oz.au (Richard A.
O'Keefe) writes:

   [File-scope] "static" is not such a big deal.  Remember, the norm
   for good C style is to have a very small number of functions in a
   file, which means that 'static' functions are expected to be rare.

Like the old punchline, "what you mean 'WE', paleface?"

Here at Applied Dynamics (plug plug), and doubtless at many other
places, we try to modularize.  All the functions that relate to one
data structure or data type are put in one file, and any local
information is declared 'static' (actually, PRIVATE).  If that makes a
large source file, well, life is full of little tragedies.

I dislike the one function==one file idea, simply because so much is
made global.  I can't easily tell where an external variable or
function is used.

(P. S.  It's a Lone Ranger joke.
   "Tonto!  Look!  Ten thousand Indian warriors have surrounded us,
   and they're about to charge!  We're about to be killed!"
)
--
Tim McDaniel                 Applied Dynamics Int'l.; Ann Arbor, Michigan, USA
Work phone: +313 973 1300                            Home phone: +313 677 4386
Internet: mcdaniel@adi.com                UUCP: {uunet,sharkey}!amara!mcdaniel

johnb@srchtec.UUCP (John Baldwin) (09/28/90)

In article <3835@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au
 (Richard A. O'Keefe) writes:
>
> while on an IBM/360 signed char was much more costly
>than signed char.  

Indeed, I CAN believe that is the case on a 360!     :-)  :-)  :-)  :-)

[typos just don't get much better than this!
 jtb-  sorry for the clutter; I couldn't resist.]

-- 
John T. Baldwin                     | "Pereant qui ante nos nostra dixerunt!"
Search Technology, Inc.             | (A plague on those who said our good
johnb%srchtec.uucp@mathcs.emory.edu |  things before we did!)