Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!husc6!cca!g-rh From: g-rh@cca.CCA.COM (Richard Harter) Newsgroups: comp.lang.c Subject: Re: Writing readable code Message-ID: <17193@cca.CCA.COM> Date: Sat, 27-Jun-87 23:21:47 EDT Article-I.D.: cca.17193 Posted: Sat Jun 27 23:21:47 1987 Date-Received: Sun, 28-Jun-87 05:03:28 EDT References: <1158@copper.TEK.COM> <6858@auspyr.UUCP> <17171@cca.CCA.COM> <22250@sun.uucp> Reply-To: g-rh@CCA.CCA.COM.UUCP (Richard Harter) Organization: Computer Corp. of America, Cambridge, MA Lines: 142 RH: Richard Harter GH: Guy Harris In article <22250@sun.uucp> guy%gorodish@Sun.COM (Guy Harris) writes: RH: When I see RH: RH: if (!p) RH: RH: I read it as RH: RH: if p is not valid then ... RH: RH: The (!p) syntax tells me that p is among the class of items that may be RH: treated as boolean (under the C language conventions) and that we are RH: testing whether it is false. This is not a matter of "saving characters"; RH: it is a matter of classification. GH: But what does it mean to say that a pointer is "false"? Pointers GH: themselves really aren't Boolean; there is a boolean predicate *on* a GH: pointer, namely the "is this pointer null" predicate. You could view GH: the construct "p", used in a context that requires a Boolean GH: expression, as really meaning "is_non_null(p)", and "!p" as meaning GH: "!is_non_null(p)", or "is_null(p)". Well now, C doesn't really have boolean types, but it does have a convention that anything which is not zero tests true and any thing which is zero tests false, and the convention that a null pointer (which we all know is 0x6000000 :-)) behaves on assignment and testing as zero. So the expression "!p" in "if (!p)" is "null pointer", i.e. not a potent- ionally legal pointer. Since that is what I am asking, I see the construct as saying what I mean. RH: When I see RH: RH: if (p != NULL) RH: RH: it tells me two rather different things. First of all it tells me that RH: p is an item for which there are one or more coded values, among which RH: is NULL, and that for all cases where p is not NULL, there is some action RH: to be taken. GH: All of which happen to be the case for pointers. Are you arguing GH: that "!p" is somehow better than "p != NULL"? This is a matter of GH: taste; if you do not view "!p" as shorthand for "is_null(p)", then "p GH: == NULL" makes more sense as a way of writing "is_null(p)", and many GH: good programmers do not view "!p" as such a shorthand. Well, as you say, it is a matter of taste. Many good programmers use "p != NULL" and many equally good programmers use "!p". However let us define FALSE as zero explictly and ask which is more reasonable to say "if (p == FALSE)" or "if (!p)", or, in English, if p is false then ... vs if not p then This is truly a matter of taste; many people would find the first form to be clearer and more comprehensible. Many other people would find the the second form equally clear or clearer, and the first form to be redundant. I suspect that people who have a background in formal logic will prefer the second form. From my viewpoint, the form "!p" asserts that "p" is in the large class of things which takes the values "true" (where true is any non null) and "false" (null) and that I am testing on whether it is false or not. Note that under this viewpoint I don't care what the specific values for "true" and "false" are -- I only care that the semantics of the language provide for a "true" and a "false". Now the chap who prefers "p == FALSE" doesn't see it that way. He sees it as a test on whether p has a specified value. This, too, is a perfectly legitimate approach. However... I take exception to those who, only understanding their own viewpoint and approach, treat any other approach based on some other viewpoint as being bad code. The person to whom I originally responded supposed that "if (!p)" was a sloppy abomination used to save characters. This is an intensely parochial view. RH: Secondly it tells me that the file that the statement is in RH: includes stdio.h (or that the author of the code is a dweeb.) And that RH: should tell me that the code in this file needs stdio.h, FOR I DO NOT RH: CONSIDER IT GOOD PROGRAMMING PRACTICE TO INCLUDE INCLUDE FILES WHICH ARE RH: NOT USED. GH: OK, so either: GH: GH: 1) stick GH: GH: #define NULL 0 GH: GH: at the front of all modules not including GH: GH: 2) say "if (p == 0)" instead of "if (p == NULL)" GH: GH: 3) in an ANSI C implementation, stick GH: GH: #include GH: GH: at the front of your module; you *are* using at least one GH: of the items it defines, namely NULL. Sorry Guy, this one I cannot buy. You third alternative is not acceptable for those of us who are writing code which runs on a variety of implementations. The first is a kludge. The second is perfectly acceptable. In point of fact we actually defined lower case null as 0 in the stddef just to avoid conflicts with stdio.h. We also have FALSE defined as 0 (obviously). So we have lots of choices. However we don't use NULL unless it is specifically referring to a null file pointer. GH: Also, you didn't address the issue of GH: GH: if (!strcmp(str1, str2)) GH: GH: which I find less defensible. "strcmp" is not really boolean; it's a GH: function from the set of strings to the set of "int"s, such that GH: there are three predicates on the result with the following GH: properties: GH: GH: strcmp(str1, str2) == 0 iff str1 == str2 GH: strcmp(str1, str2) > 0 iff str1 > str2 GH: strcmp(str1, str2) < 0 iff str1 < str2 GH: GH: (where something like "str1 == str2" refers to equality in the sense GH: of string equality, *not* in the sense of pointer equality) and, as GH: such, there are several predicates to be applied to the result of GH: "strcmp" that model various predicates that can't be applied directly GH: to strings in C. Given that, "!strcmp(str1, str2)" is "meaningful" GH: in the sense that the semantics of C give it a meaning; however, it isn't GH: "meaningful" in the sense that it very clearly suggests what you're GH: testing. "!strcmp(str1, str2)" means that the two strings are equal, GH: but someone not reading the expression carefully and just seeing the Here I have to agree -- strcmp returns, according to the semantics of C, a value of true if the strings are unequal and a value of false if they are equal. Accordingly, strcmp is not really in the category of functions which match the semantics of C. In this case, !strcmp is a trick, which is an entirely different matter. We seldom use the string library [portability, you know -- we avoid library functions, other than those we absolutely have to use] so I have never dealt with this particular issue. -- Richard Harter, SMDS Inc. [Disclaimers not permitted by company policy.] [I set company policy.]