Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!wuarchive!udel!haven!mimsy!rlgvax!scc From: scc@rlgvax.Reston.ICL.COM (Stephen Carlson) Newsgroups: comp.lang.c Subject: Re: One more point regarding = and == (more flamage) Message-ID: <1991Mar26.180311.29125@rlgvax.Reston.ICL.COM> Date: 26 Mar 91 18:03:11 GMT References: <925@isgtec.UUCP> Reply-To: scc@rlgvax.OPCR.ICL.COM (Stephen Carlson) Organization: International Computers Limited Lines: 124 In article <925@isgtec.UUCP> robert@isgtec.UUCP writes: >In article <355@smds.UUCP>, rh@smds.UUCP (Richard Harter) writes: >|> Re: >|> a) while (*foo++ = *bar++) >|> b) while (*foo ++ == *bar++) >|> c) while ((*foo++ = *bar++) != 0) >|> >|> Sundry claims have been made that (c) is "good style" versus (a). The >|> original objection was couched in terms of "testing on assignment inside >|> conditionals is bad form". IMNSHO most of the arguments and dogmatic >|> statements are so much rubbish. >Well the biggest argument has been if you use a) the maintainer can't tell >if you meant a) or b); if you use c) the maintainer KNOWS you meant a). >This isn't rubbish. The statement: while (*s++ = *t++) ; is a standard C idiom to copy two zero-terminated arrays [K&R gives this as an example implementation of strcpy()]. Any programmer that does not immediately understand this cannot be called a C programmer. The other statement: while (*s++ == *t++) ; is not well set up to compare two arrays. It does not check for a zero termination. It is really only useful when the programmer has already set up guaranteed unequal sentinals at the end of the array. Then the pointers after the loop are one greater than would be useful. The point is, for these kinds of statements, statement (a) is normal, common, and useful. Statement (b) is suspicious, rare, and useless. >|> (c) is no more or no less clean than (a). >It's just more readable. Statement (c) tries to make explicit that the assignment in a conditional is no accident, while the real case--for this kind of expressions--is that the equality is likely to be wrong. Since statement (b) is much more out of the ordinary, I would prefer some marking such as a comment or a different but equivalent coding to assert that it is really indended. The explicit marking is statement (c)'s case does just the opposite--it brings attention to the more common and more often correct construct. >|> In both cases you are testing >|> the value of the contents, not of foo, but of foo before it was incremented. >|> Does either statement say that? Not obviously -- you have to understand C, >|> get down in the muck with it, before it is is obvious. >The 'C' is obvious in all of a), b) and c); the programmers INTENT is only >obvious in b) and c)! Here, I disagree. The programmers intent is obvious in (a), unclear in (b), just annoying in (c). Any one who does immediately understand (a) is not a C programmer. As far as the general issues of assignments in conditional contexts is concerned, it is important to look that the situations they happen in: (1) Zero-terminated array copies: while (*s++ = *t++) ; The assignment is preferred because it a common C idiom, and it alternative is rare. If the alternative is really preferred, the loop should be recoded: while (*s == *t) s++, t++; s++, t++; Of course, as far as utility is concerned, the second double increment is not usually wanted (but that makes it equivalent to the alternative). (2) Set and test a function's return value. if (ret = function()) ... Being that function calls are expensive and generally cannot be redone, this form is OK for concise code, especially as a second condition as in if (flag && (ret = function())) ... Of course, one could always code: ret = function(); if (ret) ... As far as the alternative is concerned, being somewhat rarer I would prefer to have its intent clearly marked as in: if (function() == value) A missing '=' here is a compile time error. (3) All other cases. Since the test for equality is much more prevalent in all other case, the onus is on the assignment case to make that intent clear. There are several styles: if ((a = b) != 0) ... a = b; if (a) ... if (!!(a = b)) ... if ((a = b)) ... All are equivalent; all work; all indicate the intent. Try to be consistent though. Inconsistency should have a purpose. A good style should not blind but take into account to usefulness and frequency of the construct. -- Stephen Carlson | ICL OFFICEPOWER Center | In theory, theory and scc@rlgvax.reston.icl.com | 11490 Commerce Park Drive | practice are the same. ..!uunet!rlgvax!scc | Reston, VA 22091 |