awd@dbase.UUCP (Alastair Dallas) (02/04/89)
We've discussed the proper definition of NULL a great deal, and I understand that the ANSI standard now specifies it. But what about a boolean type? Please excuse me if the standard discusses this as well, but I can think of several ways to handle booleans (and I've worked on code that used all three): 1. typedef short bool; 2. typedef char bool; 3. typedef enum {FALSE=0, TRUE=1} bool; I like the last one, but it requires a compiler that doesn't complain about constructs like: bool flag = TRUE; if (flag) ... Some compilers I've run into want that to be either: if ((short) flag) or if (flag == TRUE) While this means more typing*, I'm inclined to forgo the convenience of if (flag) in favor of the self-documentation of the explicit if (flag==TRUE). I'm curious what the net thinks. Are there any other problems with using an enum? While we're at it, I'd like to hear opinions pro and con on the use of all upper case to identify typedefs--bool vs. BOOL vs. Bool. /alastair/ *No pun intended.
gwyn@smoke.BRL.MIL (Doug Gwyn ) (02/08/89)
In article <10@dbase.UUCP> awd@dbase.UUCP (Alastair Dallas) writes: >But what about a boolean type? >Please excuse me if the standard discusses this as well, but I can think >of several ways to handle booleans (and I've worked on code that used all >three): >1. typedef short bool; >2. typedef char bool; >3. typedef enum {FALSE=0, TRUE=1} bool; >I like the last one, but it requires a compiler that doesn't complain about >constructs like: > bool flag = TRUE; > if (flag) ANSI C compilers have to accept that. Enums act just like ints in expressions. Some C compilers tried to make more full-fledged types out of enumerations, with mixed success (generally unsatisfactory). One occasionally still runs into such compilers, as you've noticed. >While this means more typing*, I'm inclined to forgo the convenience of >if (flag) in favor of the self-documentation of the explicit if (flag==TRUE). If your Boolean variable is called `flag', that may be more intelligible, but what about, for example, if ( too_many ) which is more readable the other way. Generally I don't think of == or != as Boolean operators. >I'm curious what the net thinks. I don't know about the net; does it think? My typedef for `bool' is as an int, because that is the actual type of C Boolean expressions. >use of all upper case to identify typedefs--bool vs. BOOL vs. Bool. As a matter of style, if something is considered a (local) standard extension to the base language, as with my <std.h> use of `bool' and `pointer' (generic pointer type), then it should look like other keywords. Something that looks like a function should look like a function (locally that means `TooMany()' etc.). Manifest constants generally should follow existing practice and appear as all-caps. However, the most important thing is that your code be maintainable; follow whatever stylistic guidelines best enforce that.
evil@arcturus.UUCP (Wade Guthrie) (02/10/89)
In article <9609@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn ) writes: > In article <10@dbase.UUCP> awd@dbase.UUCP (Alastair Dallas) writes: > >But what about a boolean type? ack phht. Many people have been programming in C for years and have gotten quite used to C's handling of boolean (translate: int) stuff (I even like it). More importantly, any change to C to include a boolean type would make a lot of existing code break. > >of several ways to handle booleans (and I've worked on code that used all > >three): > >1. typedef short bool; > >2. typedef char bool; > >3. typedef enum {FALSE=0, TRUE=1} bool; Why make a simple idea more complicated? The only place in the code where this will make any difference is in the declarations (with, possibly, the exception of the enum form). The same thing can be done with commenting: int blah, /* this variable . . . */ fred, flag, /* boolean: set if ... */ . . . > >if (flag) in favor of the self-documentation of the explicit if (flag==TRUE). You can do that whether the type is 'int' or 'bool'. That is a matter of style and is certainly called for in many cases. > if ( too_many ) I usually try to make things look like that -- I find it takes a little more effort in the variable names, but it makes the code a lot more readable. #ifdef DIGRESSION_OKAY Now, if you want to know about putting effort into making variables understandable. . .You got a graphical object which is made up of a linked list of pieces (such as lines, square panels, etc). You need a structure for the linked list node and a separate structure for each type of piece. With this arrangement, you could implement a union of pointers to structures (each member of this union points to a different type of piece). How about this for readable variable names: struct ll_node { struct ll_node *next_piece; union { struct s_panel *panel; struct s_line *line; . . . } is_a; } object; So that in the code one might see: something = object.next_piece->is_a.panel #endif /* DIGRESSION_OKAY */ > generally I dont think of == or != as Boolean operators. Me either. Wade Guthrie evil@arcturus.UUCP Rockwell International Anaheim, CA (Rockwell doesn't necessarily believe / stand by what I'm saying; how could they when *I* don't even know what I'm talking about???)
msb@sq.uucp (Mark Brader) (02/10/89)
> 1. typedef short bool; > 2. typedef char bool; > 3. typedef enum {FALSE=0, TRUE=1} bool; The last is nicely self-documenting, as long as you understand that the language will never enforce it for you, but as you noted, some existing compilers have problems with it. (In the ANSI draft, all the constructs you want do work.) However, for ordinary use I prefer none of these. My booleans are int when they are scalars or in small arrays: I let the computer work in its favorite size. When the arrays become large enough to make space conser- vation important, then of course I switch to char -- unless the array is so big that I have to use shifts and masking to pack a boolean into each bit. I prefer not to use typedefs for boolean for two reasons. One is that I couldn't make that decision to change types according to the array size (unless I had two typedefs, of course). The other reason is that I prefer to use typedefs sparingly, because they conceal information that's sometimes useful. (I know that variable has a numerical value, but do I need %d format to print it, or %ld or %u or %lu or %g...?) Basically I reserve typedefs for occasions when they will significantly enhance either brevity or modularity. Typedefing boolean does neither, but only adds a bit (no pun intended) of documentation. This can be done just as well with a comment beside the declaration, or better yet, by choosing a suitable name for the variable itself. Thus, instead of this... I prefer this... boolean sex; int is_female; /* boolean */ struct country { struct country { char name[CNAMELEN+1]; char name[CNAMELEN+1]; boolean driving; char drives_on_right; /* boolean */ } country[200]; } country[200]; The worst thing a person who defines TRUE and FALSE can do, though, is "if (x == TRUE)". This is a true abomination. If the variable is true to its logical type, it is true that this is equivalent to "if (x)", but it's also true that it's very likely to be slower. And if the variable is *not* true to its logical type, i.e. if it may sometimes have a value other than 0 or 1, then the code becomes extremely tricky for the logical programmer to debug! (All puns intended. For the benefit of non-users of FORTRAN: "logical" is the name of the boolean type in that language.) On the other hand, "is_female = TRUE;" is reasonable. Some days I even prefer it to the alternatives. > use of all upper case to identify typedefs--bool vs. BOOL vs. Bool. I figure typedefs are almost like macros, so I use BOOL. Opinions vary. Mark Brader, SoftQuad Inc., Toronto, utzoo!sq!msb, msb@sq.com #define MSB(type) (~(((unsigned type)-1)>>1))
karl@haddock.ima.isc.com (Karl Heuer) (02/11/89)
In article <3645@arcturus> evil@arcturus.UUCP (Wade Guthrie) writes: >>In article <10@dbase.UUCP> awd@dbase.UUCP (Alastair Dallas) writes: >>>But what about a boolean type? > >ack phht. Many people have been programming in C for years and have >gotten quite used to C's handling of boolean (translate: int) stuff >(I even like it). The same could have been said of `void'% before it was added to C. Just because it's possible to do without it doesn't make it a bad idea. >More importantly, any change to C to include a boolean type would make a lot >of existing code break. Nonsense. I can easily come up with a model that is useful, yet completely backward compatible with existing code (modulo the new keyword, and even that can be avoided). >The same thing can be done with commenting: > int flag, /* boolean: set if ... */ Adding it to the language would make the information available to the compiler as well as the reader. This would allow more errors to be caught at compile time, and it could sometimes produce better code. Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint ________ % I'm sure there are some Neanderthals out there that still eschew `void'. You need not reply just to state your existence.
chris@mimsy.UUCP (Chris Torek) (02/11/89)
In article <3645@arcturus> evil@arcturus.UUCP (Wade Guthrie) writes: >Why make a simple idea more complicated? Indeed. Perhaps the biggest problem with boolean types, and definitions for `TRUE' and `FALSE' (or True and False or true and false or . . .) is exemplified by the QDSS driver supplied with 4.3BSD-tahoe (for which no one at Berkeley is at fault). It had the following definitions (somewhat paraphrased): #define FALSE 0 #define TRUE ~FALSE ... /* these macros return TRUE when the queue is empty/full/... */ #define ISEMPTY(eq) ((eq)->head.foo == (eq)->tail.foo) The code then read if (ESEMPTY(eq) == TRUE) bar(); It is left as an exercise to the reader to determine why this test will never call function bar(). -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
mcdonald@uxe.cso.uiuc.edu (02/11/89)
> #define FALSE 0 > #define TRUE ~FALSE ... > /* these macros return TRUE when the queue is empty/full/... */ > #define ISEMPTY(eq) ((eq)->head.foo == (eq)->tail.foo) >The code then read > if (ESEMPTY(eq) == TRUE) bar(); >It is left as an exercise to the reader to determine why this test >will never call function bar(). And on some computers (FALSE == TRUE) returns 0, while on others (FALSE == TRUE) will return 1! (Hint: There are a few, a very few, C compilers for one's complement machines, and on some of those 0 == -0). I admit this is farfetched.
jas@ernie.Berkeley.EDU (Jim Shankland) (02/12/89)
In article <15906@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: >Perhaps the biggest problem with boolean types, and definitions for >`TRUE' and `FALSE' ... is exemplified by ...: > > #define FALSE 0 > #define TRUE ~FALSE > ... > /* these macros return TRUE when the queue is empty/full/... */ > #define ISEMPTY(eq) ((eq)->head.foo == (eq)->tail.foo) > >The code then read > > if (ESEMPTY(eq) == TRUE) bar(); Bleck. But this is no more an argument against boolean types than an incompetent surgeon is an argument against surgery. First, TRUE ought to be defined to be the same value returned by relops: 1. Second, as Mark Brader has pointed out, "if (<bool-val> == TRUE)" is an abomination. Do you say, "If the weather's nice tomorrow is true, I'll have a picnic"? Or "If the queue is empty is true, I'd better call bar()"? I agree with Karl Heuer: C would have benefited from a built-in boolean type. As is, conscientious programmers will avoid type punning between values that are conceptually boolean with those that are conceptually integers (though as far as C is concerned, of course they're both integers.) Jim Shankland jas@ernie.berkeley.edu "I've been walking in a river all my life, and now my feet are wet"
les@chinet.chi.il.us (Leslie Mikesell) (02/13/89)
In article <27989@ucbvax.BERKELEY.EDU> jas@ernie.Berkeley.EDU.UUCP (Jim Shankland) writes: >I agree with Karl Heuer: C would have benefited from a built-in boolean >type. Or perhaps a boolean equality operator for people who don't like the looks of: (1) if (expression) action(); and prefer: (2) if (expression == SOMETHING) action(); and who don't like: (3) if (expression != 0) action(); Method (2) would work (and look better to some people) if C had a boolean equality operator that would evaluate false only when one of the operands is zero and one non-zero. This would have an advantage over a separate data type in that you would not have to convert the return values from all those functions that return 0 for failure, some (useful, non-boolean) value on success. Les Mikesell
bph@buengc.BU.EDU (Blair P. Houghton) (02/13/89)
In article <27989@ucbvax.BERKELEY.EDU> jas@ernie.Berkeley.EDU.UUCP (Jim Shankland) writes: > >I agree with Karl Heuer: C would have benefited from a built-in boolean >type. As is, conscientious programmers will avoid type punning between >values that are conceptually boolean with those that are conceptually >integers (though as far as C is concerned, of course they're both integers.) Low-sophistication point-of-interest, approx. 20 mills in value: You can be conscientious if, when unsure of the return value, and you _like_ having true==1 and false==0, then say boolfoo = !!expr_returning_funny_bools; which, according to my KnR, should never ever give any boolfoo other than 0 or 1, even if the expr has a dozen different values for true. (See the description of the '!' op. I think it's around page 187 of ed. 1.) --Blair "!!(But I can't be sure...)"
bill@twwells.uucp (T. William Wells) (02/13/89)
In article <2113@buengc.BU.EDU> bph@buengc.bu.edu (Blair P. Houghton) writes:
: boolfoo = !!expr_returning_funny_bools;
:
: which, according to my KnR, should never ever give any boolfoo other
: than 0 or 1, even if the expr has a dozen different values for true.
It'll work, but try
boolfoo = expr_returning_funny_bools != 0;
It's clearer.
---
Bill
{ uunet!proxftl | novavax } !twwells!bill
evil@arcturus.UUCP (Wade Guthrie) (02/14/89)
Attempting to fill the part of those called 'reader': In article <15906@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes: > #define FALSE 0 > #define TRUE ~FALSE /* TRUE has the bit pattern 1111 ... 1111, not 0000 ... 0001 */ > ... > /* these macros return TRUE when the queue is empty/full/... */ > #define ISEMPTY(eq) ((eq)->head.foo == (eq)->tail.foo) /* causing the macro ISEMPTY to evaluate to 1 or 0 */ > The code then read > > if (ESEMPTY(eq) == TRUE) bar(); /* * since 1111 ... 1111 never equals either 1 or 0, * bar() never gets called */ > It is left as an exercise to the reader to determine why this test > will never call function bar(). Do I pass the test? Wade Guthrie evil@arcturus.UUCP Rockwell International Anaheim, CA (Rockwell doesn't necessarily believe / stand by what I'm saying; how could they when *I* don't even know what I'm talking about???)
diamond@csl.sony.JUNET (Norman Diamond) (02/14/89)
In article <15906@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes: > Perhaps the biggest problem with boolean types, and definitions for > `TRUE' and `FALSE' (or True and False or true and false or . . .) > #define FALSE 0 > #define TRUE ~FALSE > ... > /* these macros return TRUE when the queue is empty/full/... */ > #define ISEMPTY(eq) ((eq)->head.foo == (eq)->tail.foo) > ... > if (ESEMPTY(eq) == TRUE) bar(); > It is left as an exercise to the reader to determine why this test > will never call function bar(). A boolean operator would make it work correctly: #define TRUE !FALSE Of course, TRUE and FALSE *should* be used only as the right-hand-sides of assignments, not as operands for a comparison. However, it is not correct to say that the biggest problem with <x> is that some programmer codes a bug in which he forgets to use <x>'s operators.
scs@adam.pika.mit.edu (Steve Summit) (02/19/89)
In article <7698@chinet.chi.il.us> les@chinet.chi.il.us (Leslie Mikesell) writes: >Or perhaps a boolean equality operator for people who don't like the looks >of: >(1) if (expression) action(); >and prefer: >(2) if (expression == SOMETHING) action(); >Method (2) would work (and look better to some people) if C had a boolean >equality operator that would evaluate false only when one of the operands >is zero and one non-zero. How silly. The thing to do is educate those "people who don't like the looks of if(expression)". Who are they, anyway? If an expression is of "conceptual type boolean," and especially if its name reflects it ("inputready()", "break_seen", etc.) then if(expression) is the most natural way to write it. If the expression is not "conceptually boolean," then an explicit comparison is correct and appropriate. Comparison operators can be thought of as converting ints to bools, to be handed to things like "if". Who needs a new operator to convert bools to bools? Steve Summit scs@adam.pika.mit.edu
rickc@pogo.GPID.TEK.COM (Rick Clements) (02/28/89)
In article <1989Feb10.092449.20875@sq.uucp> msb@sq.com (Mark Brader) writes: }} 1. typedef short bool; }} 2. typedef char bool; }} 3. typedef enum {FALSE=0, TRUE=1} bool; }The last is nicely self-documenting, as long as you understand that the }language will never enforce it for you, but as you noted, some existing }compilers have problems with it. (In the ANSI draft, all the constructs }you want do work.) }However, for ordinary use I prefer none of these. My booleans are int }when they are scalars or in small arrays: I let the computer work in its }favorite size. I always use chars. This lets the machine I am working on (an 68HC11) work in its favorite size. Everyone assumes an int is the natural size of the machine, but an int is at least 16 bits. }Basically I reserve typedefs for occasions when they will significantly }enhance either brevity or modularity. Typedefing boolean does neither, }but only adds a bit (no pun intended) of documentation. This can be done }just as well with a comment beside the declaration, or better yet, by }choosing a suitable name for the variable itself. I perfer to use typedef's for the extra documentation. Also, if I work on code that might be ported, it is easy to change to match the machine. }The worst thing a person who defines TRUE and FALSE can do, though, is }"if (x == TRUE)". This is a true abomination. If the variable is true to }its logical type, it is true that this is equivalent to "if (x)", but it's }also true that it's very likely to be slower. And if the variable is }*not* true to its logical type, i.e. if it may sometimes have a value }other than 0 or 1, then the code becomes extremely tricky for the logical }programmer to debug! With the compiler I am currently using, I use "if (x == FALSE)" or "if (x != FALSE). This doesn't have an ambiguity because of multiple true values. The compiler I am using generates LESS code this way. ("if (x)" causes it to go to the work of converting it to a 1 or 0 with some less than efficient code. That is ignoring the fact the whole process it unneeded.) PROM space is tight, so this becomes important. It also helps when you want to get an entire sequence on a logic analyzer trace. -- Rick Clements (RickC@pogo.GPID.TEK.COM)
gwyn@smoke.BRL.MIL (Doug Gwyn ) (03/01/89)
In article <6849@pogo.GPID.TEK.COM> rickc@pogo.GPID.TEK.COM (Rick Clements) writes: >With the compiler I am currently using, I use "if (x == FALSE)" or >"if (x != FALSE). ... The compiler I am using generates LESS code >this way. ("if (x)" causes it to go to the work of converting it to >a 1 or 0 with some less than efficient code. That's pretty strange -- "if(x)" means no more and no less than "if x is nonzero", which nearly all instruction sets support directly. It's easy to imagine a dumb compiler that produces MORE code for "if(x!=0)" but not one that produces LESS code.
guy@auspex.UUCP (Guy Harris) (03/02/89)
>With the compiler I am currently using, I use "if (x == FALSE)" or >"if (x != FALSE). This doesn't have an ambiguity because of multiple >true values. The compiler I am using generates LESS code this way. >("if (x)" causes it to go to the work of converting it to a 1 or 0 >with some less than efficient code. That is ignoring the fact the >whole process it unneeded.) Yup, it sure is unneeded. Why is the compiler in question so dumb? >PROM space is tight, so this becomes important. Are there any smart compilers for the chip in question? If so, you might want to pick them up, given that PROM space *is* so tight....
jeenglis@nunki.usc.edu (Joe English) (03/02/89)
gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: >In article <6849@pogo.GPID.TEK.COM> rickc@pogo.GPID.TEK.COM (Rick Clements) writes: >>With the compiler I am currently using, I use "if (x == FALSE)" or >>"if (x != FALSE). ... The compiler I am using generates LESS code >>this way. ("if (x)" causes it to go to the work of converting it to >>a 1 or 0 with some less than efficient code. > >That's pretty strange -- "if(x)" means no more and no less than >"if x is nonzero", which nearly all instruction sets support directly. >It's easy to imagine a dumb compiler that produces MORE code for >"if(x!=0)" but not one that produces LESS code. I once had to work with a compiler that was broken in a similar way: boolean expressions would calculate either a 0 or a 1, then test that result and branch accordingly. This generated *three unnecessary instructions* for every relational expression. (And the fourth pass of the compiler was called the "optimizer!" I don't think it did a very good job of optimizing...) If I recall correctly, it generated the same amount of code for "if(x)" and "if(x!=0)," but it went something like: Compare x and zero; move 1 into AX; if test yielded equal, skip next instruction; move 0 into AX; Then it would do an "OR AX,AX" and branch accordingly. Shocking, but true. Before you ask (so you can avoid purchasing it :-), the compiler in question is an old (c. 1984) version of Computer Innovation's C86, I think somewhere around version 1.2. --Joe English jeenglis@nunki.usc.edu
gwyn@smoke.BRL.MIL (Doug Gwyn ) (03/02/89)
In article <2892@nunki.usc.edu> jeenglis@nunki.usc.edu (Joe English) writes: -gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: ->That's pretty strange -- "if(x)" means no more and no less than ->"if x is nonzero", which nearly all instruction sets support directly. ->It's easy to imagine a dumb compiler that produces MORE code for ->"if(x!=0)" but not one that produces LESS code. -If I recall correctly, it generated the same amount of code -for "if(x)" and "if(x!=0)," but it went something like: I can also believe that a compiler would produce exactly same code for "if(x)" and "if(x!=0)", even if it's horrible code in both cases. I still wonder how one could get WORSE code for "if(x)", though.