byron@archone.tamu.edu (Byron Rakitzis) (03/22/91)
I have one more thing to say to the self-styled C gods who approve of simple assignments as an implicit test against zero inside an if-statment. It's this: There is no way when you see the code-fragment a) while (*foo++ = *bar++) to tell whether a copy of data in strcpy fashion is intended, or whether this should have been a strcmp-like loop: while (*foo++ == *bar++) One is forced to gather from the context of the program just what the programmer intended. Now in this case, it may be "obvious" what the intent of the programmer is, but I don't think anyone can doubt that the first instance is rendered UNAMBIGUOUS by the addition: b) while ((*foo++ = *bar++) != 0) All I can say is, if you code in style (a) rather than style (b), don't expect anyone reading your code to enjoy the experience. Henry, are you behind me on this one? What do the coding style people say anyway?
bhoughto@pima.intel.com (Blair P. Houghton) (03/22/91)
In article <13603@helios.TAMU.EDU> byron@archone.tamu.edu (Byron Rakitzis) writes: >It's this: There is no way when you see the code-fragment >a) while (*foo++ = *bar++) >to tell whether a copy of data in strcpy fashion is intended, or whether >this should have been a strcmp-like loop: > while (*foo++ == *bar++) >the first instance is rendered UNAMBIGUOUS by the addition: >b) while ((*foo++ = *bar++) != 0) Or by the additions: /* copy bytes till end of string */ while (*foo++ = *bar++) /* compare bytes till there's a difference */ while (*foo++ == *bar++) /* mommy: please hold my hand */ while ((*foo++ = *bar++) != 0) Basically, if you're worth the meager pittance they direct-deposit into your debt with the Company Store, the comments will have existed long before you wrote the code. Put those in, and make them accurate, and it doesn't matter how much the code obfuscates. It's called top-down design, and involves _thinking_ before you start making mistakes. --Blair "Back to basics."
byron@archone.tamu.edu (Byron Rakitzis) (03/22/91)
In article <3182@inews.intel.com> bhoughto@pima.intel.com (Blair P. Houghton) writes: -In article <13603@helios.TAMU.EDU> byron@archone.tamu.edu (Byron Rakitzis) writes: ->the first instance is rendered UNAMBIGUOUS by the addition: ->b) while ((*foo++ = *bar++) != 0) - -Or by the additions: - - /* mommy: please hold my hand */ - while ((*foo++ = *bar++) != 0) - -Basically, if you're worth the meager pittance they direct-deposit -into your debt with the Company Store, the comments will have -existed long before you wrote the code. Put those in, and make -them accurate, and it doesn't matter how much the code obfuscates. - -It's called top-down design, and involves _thinking_ before -you start making mistakes. - Using comments to explain away obfuscation when a simple alternative is possible is *very* poor practise, in my view. How about: i++; and /* increment the value of i, when i is nonzero (but if you look at the code 2 lines above, you'll see that i is never zero at this point) */ i -=- i/i;
hagins@gamecock.rtp.dg.com (Jody Hagins) (03/23/91)
In article <13603@helios.TAMU.EDU>, byron@archone.tamu.edu (Byron Rakitzis) writes: |> I have one more thing to say to the self-styled C gods who approve of |> simple assignments as an implicit test against zero inside an if-statment. |> |> It's this: There is no way when you see the code-fragment |> |> a) while (*foo++ = *bar++) |> |> to tell whether a copy of data in strcpy fashion is intended, or whether |> this should have been a strcmp-like loop: |> |> while (*foo++ == *bar++) |> |> One is forced to gather from the context of the program just what the |> programmer intended. Now in this case, it may be "obvious" what the |> intent of the programmer is, but I don't think anyone can doubt that |> the first instance is rendered UNAMBIGUOUS by the addition: |> |> b) while ((*foo++ = *bar++) != 0) |> |> |> All I can say is, if you code in style (a) rather than style (b), don't |> expect anyone reading your code to enjoy the experience. |> |> Henry, are you behind me on this one? What do the coding style people say |> anyway? |> Well, I'm not Henry, but I definitely agree here! Also, Borland seems to agree here as well, since while(*foo++ = *bar++); will generate a warning message. One point here: Why go to the bother of commenting your code if you use statements like this? These seem counterproductive. I know, I know, comments will tell you what the meaning of the code is, but by using the comparison to 0, you do not have to specify in your comment that you, in fact, meant to use '=' instead of '=='. Also, (b) sure does make the code alot easier to maintain, especially when the maintainer is not the original developer. Why use comments when you refuse to use good style? You might as well write all your code in BASIC! You know, there is an example in the Bible about this. Paul had to confront the converts to Christianity who still insisted that every male had to be circumcised. He was indignant that they still held to part of "the old law." He says in Galations 5:12 (NIV) "As for those agitators, I wish they would go the whole way and emasculate themselves!" Now, I'm not saying that those who want to keep their bad programming habits must emasculate (efeminate ;-) themselves, but if the shoe fits... :-):-):-) -- Jody Hagins hagins@gamecock.rtp.dg.com Data General Corp. 62 Alexander Dr. RTP, N.C. 27709 (919) 248-6035 Nothing I ever say reflects the opinions of DGC.
henry@zoo.toronto.edu (Henry Spencer) (03/23/91)
In article <13603@helios.TAMU.EDU> byron@archone.tamu.edu (Byron Rakitzis) writes: >a) while (*foo++ = *bar++) >b) while ((*foo++ = *bar++) != 0) > >All I can say is, if you code in style (a) rather than style (b), don't >expect anyone reading your code to enjoy the experience. > >Henry, are you behind me on this one? ... Yes. Deliberately using a construct that looks like a well-known and subtle programming error is a mistake. Your successor, reading your code, should *never* have to ask himself "is this really right?"; if there is reason for doubt, either comment the code or change it. For that matter, my personal opinion is that relying on C's implicit comparison against zero in conditionals is usually a mistake, barring one or two special cases like variables that are deliberately used only as booleans. That's a broader and more debatable point, though. -- "[Some people] positively *wish* to | Henry Spencer @ U of Toronto Zoology believe ill of the modern world."-R.Peto| henry@zoo.toronto.edu utzoo!henry
hagins@gamecock.rtp.dg.com (Jody Hagins) (03/23/91)
In article <3182@inews.intel.com>, bhoughto@pima.intel.com (Blair P. Houghton) writes: |> In article <13603@helios.TAMU.EDU> byron@archone.tamu.edu (Byron Rakitzis) writes: |> >It's this: There is no way when you see the code-fragment |> >a) while (*foo++ = *bar++) |> >to tell whether a copy of data in strcpy fashion is intended, or whether |> >this should have been a strcmp-like loop: |> > while (*foo++ == *bar++) |> >the first instance is rendered UNAMBIGUOUS by the addition: |> >b) while ((*foo++ = *bar++) != 0) |> |> Or by the additions: |> |> /* copy bytes till end of string */ |> while (*foo++ = *bar++) |> |> /* compare bytes till there's a difference */ |> while (*foo++ == *bar++) |> |> /* mommy: please hold my hand */ |> while ((*foo++ = *bar++) != 0) |> |> Basically, if you're worth the meager pittance they direct-deposit |> into your debt with the Company Store, the comments will have |> existed long before you wrote the code. Put those in, and make |> them accurate, and it doesn't matter how much the code obfuscates. |> |> It's called top-down design, and involves _thinking_ before |> you start making mistakes. You know, I used to think this way too, while I was still an amateur. "If you're worth the meager pittance they direct-deposit into your debt with the Company Store" then you will not leave a job half-done. You will complete it by adding to the documentation clear, unambiguous code. |> |> --Blair |> "Back to basics." |> -Jody Jody Hagins hagins@gamecock.rtp.dg.com Data General Corp. 62 Alexander Dr. RTP, N.C. 27709 (919) 248-6035 Nothing I ever say reflects the opinions of DGC.
gwyn@smoke.brl.mil (Doug Gwyn) (03/23/91)
In article <13603@helios.TAMU.EDU> byron@archone.tamu.edu (Byron Rakitzis) writes: >I have one more thing to say to the self-styled C gods who approve of >simple assignments as an implicit test against zero inside an if-statment. If that was intended as criticism of me in particular, all I can say about it is that one should understand the gods before criticizing them. >b) while ((*foo++ = *bar++) != 0) That's in fact the way I would code this particular case, which I consider a "straw man". On the other hand, I frequently write code such as: bool status; ... if ( status = WriteHeader() ) ... else ... return status; for which I would be extremely annoyed to receive gratuitous warnings from the compiler!
mckulka@eldalonde.endor.cs.psu.edu (Christopher Mc Kulka) (03/23/91)
In article <3182@inews.intel.com> bhoughto@pima.intel.com (Blair P. Houghton) writes: [STUFF DELETED] > /* mommy: please hold my hand */ > while ((*foo++ = *bar++) != 0) > >Basically, if you're worth the meager pittance they direct-deposit >into your debt with the Company Store, the comments will have >existed long before you wrote the code. Put those in, and make >them accurate, and it doesn't matter how much the code obfuscates. > >It's called top-down design, and involves _thinking_ before >you start making mistakes. Ahhh, it must be perfect in a perfect world where people do not make mistakes by *ACCIDENT*. Have you never missed an '=' or slipped in a ';' instead of a ',', or etc. Last time I checked I usually found mistakes after *thinking* I did not make any. Chris PS - If you have discovered a tonic that makes it possible to write programs larger than "Hello, world." correctly the first time, PLEASE let the rest of us know about it. We can *bury* Japan in a year. -- Just say *NO* to software patents & look-and-feel lawsuits. Try competition. If God had intended man to smoke he would have set him on fire. There are two ways to write an error-free program. Only the third works. Chris McKulka (mckulka@bree.endor.cs.psu.edu)
bhoughto@pima.intel.com (Blair P. Houghton) (03/23/91)
In article <q95Gsdc61@cs.psu.edu> mckulka@eldalonde.endor.cs.psu.edu (Christopher Mc Kulka) writes: >In article <3182@inews.intel.com> bhoughto@pima.intel.com (Blair P. Houghton) writes: >>It's called top-down design, and involves _thinking_ before >>you start making mistakes. > >Ahhh, it must be perfect in a perfect world where people do not make mistakes >by *ACCIDENT*. Have you never missed an '=' or slipped in a ';' instead of a >',', or etc. Very little starts out bug-free, and very little more ends up bug-free. RTFM lint(1), adb(1), and man(7). >Last time I checked I usually found mistakes after *thinking* I did not make >any. I never think that, nor do I add irrelevant and redundant code which could add errors as easily as prevent them. I test my code, thoroughly and mercilessly, and if it's defective I offer to repair or replace it, at my discretion :-). >PS - If you have discovered a tonic that makes it possible to write programs > larger than "Hello, world." correctly the first time, PLEASE let the rest > of us know about it. We can *bury* Japan in a year. That depends on what you mean by "first time." As far as I'm concerned it's not actually written until it's shar'red up and sent off to Rich $alz, and then that's only Draft_0. RTFM diff(1) and patch(1gnu). We're already burying Japan. It's a well-known fact that the Japanese have been writing the sloggingest software in the history of computing since they discovered it takes instructions to motivate an instruction set. America owns the software industry [*]. (However, they are getting a massive lead in the natural-language-processing arena; one Japanese company has a program that will translate Japanese into English at 3000 words per hour). The grander point here is that if ( (*x = *y) != 0 ) tells me nothing, and the `!= 0' part merely tells me a piece of the nothing that I already know; in fact, I'm likely to examine the expression `(*x = *x) != 0' and compare its result to zero, in my head, just as the object code will do if the compiler doesn't know diddly about optimization. If you're going to bother adding information to your thesis, at least make it constructive and not obfuscatorily redundant. --Blair "/* end of posting */" /* the following must, therefore, be a bug */ [*] If you want to bury the Japanese in manufacturing, as well, well, that'll take a few dozen years of sweeping educational reform; it has to do with the consistent and widespread ability of the people understand the technologies they are implementing. We still think we're hot shit as a nation if Americans dominate Billboard's Top 40. P.P.S. What is this, talk.politics.flame.c.japanese?
ark@alice.att.com (Andrew Koenig) (03/24/91)
In article <3182@inews.intel.com> bhoughto@pima.intel.com (Blair P. Houghton) writes: > Basically, if you're worth the meager pittance they direct-deposit > into your debt with the Company Store, the comments will have > existed long before you wrote the code. Put those in, and make > them accurate, and it doesn't matter how much the code obfuscates. Not everyone agrees that comments should explain what code does on a line-by-line level. The trouble is that if a comment restates what an obvious piece of code does, then it's just clutter -- and if it says something different from the code then something is seriously wrong. People bring me a lot of broken programs to help fix. The first thing I do when looking at such a program is to cover up the comments and insist that the author not attempt to explain the program to me. All too often the bug has been that the code misstated the author's intent, although that intent was correctly stated in the comments. Stragetic comments are extremely important: ``this section ensures that database X reflects the changes made to database Y.'' Tactical comments, however, are sometimes of negative worth. As to the original question, I stand by the recommendation I made in `C Traps and Pitfalls:' if you have an assignment as the top-level operator in a test, such as if(a=b), rewriting it as if((a=b)!=0) will make your intentions obvious in a way that the original never will. -- --Andrew Koenig ark@europa.att.com
steve@taumet.com (Stephen Clamage) (03/24/91)
bhoughto@pima.intel.com (Blair P. Houghton) writes: >Basically, if you're worth the meager pittance they direct-deposit >into your debt with the Company Store, the comments will have >existed long before you wrote the code. Put those in, and make >them accurate, and it doesn't matter how much the code obfuscates. >It's called top-down design, and involves _thinking_ before >you start making mistakes. The compiler doesn't check comments, and there is never any guarantee that a comment matches the adjoining code. The code or the comment may have been in error from the day it was written; the code may have been changed without proper modification of the comment; the comment may have been modified without proper modification of the code. It is not enough to say that a programmer worth his pay ensures that the comments are always present and correct. My rejoinder is that such a programmer should always think before making mistakes, and never write incorrect code. If you know any programmers like this who also complete their programs, let me know; we have some job openings. -- Steve Clamage, TauMetric Corp, steve@taumet.com
ghelmer@dsuvax.uucp (Guy Helmer) (03/24/91)
In <1991Mar22.161333.24290@dg-rtp.dg.com> hagins@gamecock.rtp.dg.com (Jody Hagins) writes: >Well, I'm not Henry, but I definitely agree here! Also, Borland seems >to agree here as well, since while(*foo++ = *bar++); will generate a ^ >warning message. It would be nice to have a compiler that would flag unintended empty statements, too :-) >Jody Hagins -- Guy Helmer | helmer@sdnet.bitnet Dakota State University | dsuvax!ghelmer@wunoc.wustl.edu (605) 256-5264, (605) 256-2788 | uunet!dsuvax!ghelmer Ahh, if weddings were as easy to design as software...
bhoughto@nevin.intel.com (Blair P. Houghton) (03/24/91)
In article <632@taumet.com> steve@taumet.com (Stephen Clamage) writes: >bhoughto@pima.intel.com (Blair P. Houghton) writes: >>Put [comments] in, and make >>them accurate, and it doesn't matter how much the code obfuscates. Yep. I said "accurate", all right. >The compiler doesn't check comments, and there is never any guarantee >that a comment matches the adjoining code. The compiler doesn't give a doo-doo that you included the explicit compare-not-equal-to-zero, either (modulo optimization). Comments are for humans. I make no apologies for idiots who happen to learn to type program tokens in cc'able order. There's never any guarantee that the code matches the spec, nor any that the spec matches the enhancement request, nor especially any that the enhancement request matches the performance needing improvement. Hey, the real world encroaches. I simply consider /* assign-cum-check */ if ( a=b ) more expressive, readable, correct, and professional than if ( (a=b) != 0 ) --Blair "/* flames to /dev/null */ if ( !dev ) flame_away();"
rh@smds.UUCP (Richard Harter) (03/24/91)
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. C is a language in which perversion is inherent. In this case the perversions are (a) The lack of a Boolean type, and (b) using assignments as expressions with values. The latter is an abomination and an uncleanliness that makes for obscure and baroque code no matter how it is used. It is a systemic semantic type confusion which overloads statements, expressions, and values. It is however, quite convenient. (c) is no more or no less clean than (a). 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 argument, such as it is, for (c) is that the expression being tested is a boolean expression whereas in (a) it is an integer [or a char or a pointer or a ...]. But that is a different argument, one that says one should not test on any thing except Booleans. If it makes you happy, fine. Go for it; transform all tests into Boolean expressions. Know, though, that in your heart you are not a C programmer. C has very simple and explicit rules about conditional tests. In Fortran and Pascal you test against true and false; in C you test against 0 and non-zero. Sticking an irrelevant !=0 into the test is no more than another of the many ways that people have of trying to convert C into some other language. Saying that it is clearer is no more than saying "I want to read C and see Pascal". Now where did I put that abestos vest? -- Richard Harter, Software Maintenance and Development Systems, Inc. Net address: jjmhome!smds!rh Phone: 508-369-7398 US Mail: SMDS Inc., PO Box 555, Concord MA 01742 This sentence no verb. This sentence short. This signature done.
stanley@phoenix.com (John Stanley) (03/25/91)
ghelmer@dsuvax.uucp (Guy Helmer) writes: > In <1991Mar22.161333.24290@dg-rtp.dg.com> hagins@gamecock.rtp.dg.com (Jody Ha > >Well, I'm not Henry, but I definitely agree here! Also, Borland seems > >to agree here as well, since while(*foo++ = *bar++); will generate a > ^ > >warning message. > > It would be nice to have a compiler that would flag unintended empty > statements, too :-) If you can write a compiler that can tell the difference between intended and unintended empty statements, why not write one that writes the code, too? :-)
gwyn@smoke.brl.mil (Doug Gwyn) (03/25/91)
In article <355@smds.UUCP> rh@smds.UUCP (Richard Harter) writes: >But that is a different argument, one that says one should not test on any >thing except Booleans. If it makes you happy, fine. Go for it; transform >all tests into Boolean expressions. Know, though, that in your heart you >are not a C programmer. C has very simple and explicit rules about >conditional tests. In Fortran and Pascal you test against true and false; >in C you test against 0 and non-zero. Sticking an irrelevant !=0 into the >test is no more than another of the many ways that people have of trying >to convert C into some other language. Saying that it is clearer is no >more than saying "I want to read C and see Pascal". Gee, I guess I'm not a C programmer, according to your criterion. I have found to the contrary that introduction of an explicit Boolean type, used completely and consistently, makes C source more intelligible and more likely to be correct. I would agree with an assertion that a C programmer ought to fully understand the traditional mixed numerical and Boolean usage, but I don't recommend coding in such a style.
robert@isgtec.UUCP (Robert Osborne) (03/25/91)
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. |> (c) is no more or no less clean than (a). It's just more readable. |> 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)! |> The argument, such |> as it is, for (c) is that the expression being tested is a boolean expression |> whereas in (a) it is an integer [or a char or a pointer or a ...]. |> |> But that is a different argument, one that says one should not test on any |> thing except Booleans. If it makes you happy, fine. Go for it; transform |> all tests into Boolean expressions. Know, though, that in your heart you |> are not a C programmer. And don't comment (or comment in katakana :-) for that macho 'I'm a *REAL* C programmer' feeling. |> C has very simple and explicit rules about conditional tests. Beautiful isn't it (NOT a flame :-). |> In Fortran and Pascal you test against true and false; |> in C you test against 0 and non-zero. Sticking an irrelevant !=0 into the |> test is no more than another of the many ways that people have of trying |> to convert C into some other language. Saying that it is clearer is no |> more than saying "I want to read C and see Pascal". No, saying it is clearer is know more than saying "I want to read C and see the developers intent". The C should be a concise as possible, with 'possible' being defined as 'developer's intent is very clear'. Trying to convert C into some other language means using #define EQ ==. |> Richard Harter, Software Maintenance and Development Systems, Inc. ^^^^^^^^^^^ you should know better :-) Rob. --- Robert A. Osborne ...uunet!utai!lsuc!isgtec!robert or robert@isgtec.uucp
karln@uunet.uu.net (03/26/91)
In article <632@taumet.com> steve@taumet.com (Stephen Clamage) writes: >bhoughto@pima.intel.com (Blair P. Houghton) writes: > >The compiler doesn't check comments, and there is never any guarantee >that a comment matches the adjoining code. The code or the comment >may have been in error from the day it was written; the code may >have been changed without proper modification of the comment; the >comment may have been modified without proper modification of the code. And what does any of this have to do with the compiler? > >It is not enough to say that a programmer worth his pay ensures that >the comments are always present and correct. My rejoinder is that >such a programmer should always think before making mistakes, and never >write incorrect code. 1: Your contradicting/answering your first statement, which had no point anyway. 2: Your saying programmers should think, which was the point of the comment you were responding to. What are you trying to do? Take credit for the other intellegent comment, or just avoid working for a while? > If you know any programmers like this who also > complete their programs, let me know; we have some job openings. >-- >Steve Clamage, TauMetric Corp, steve@taumet.com Maybe your company should invest heavily on CASE tools, then the end user can write the programs and you would not have a problem with programmers that cannot think nor finish the program they started ... P.S. Let me now say that I appologize to all those who have to skip this non-C nonsense, as well as the reply posting Mr Clamage is just going to *have* to make. I know this type. Remember: Brain FIRST then MOUTH!! Karl Nicholas karln!karln@uunet.uu.net
rh@smds.UUCP (Richard Harter) (03/26/91)
In article <15563@smoke.brl.mil>, gwyn@smoke.brl.mil (Doug Gwyn) writes: > Gee, I guess I'm not a C programmer, according to your criterion. Now Doug, I may have hutzpah, but not enough to say anything like that. :-) > I have found to the contrary that introduction of an explicit Boolean > type, used completely and consistently, makes C source more > intelligible and more likely to be correct. Would it shock you to learn my code regularly uses an explicit Boolean type and that TRUE and FALSE are always defined? I thought so. However that is not the really the issue at hand. > I would agree with an assertion that a C programmer ought to fully > understand the traditional mixed numerical and Boolean usage, but > I don't recommend coding in such a style. For the most part we probably agree. In the case in point, however, the issue is not really one of mixed numerical and Boolean usage. The C conditional really is one of testing between invalid (formally 0) and valid (not 0). Before someone objects that the test is numeric, think again. You can say if(pointer) or if(char). While it is true that char's can be converted to ints, pointers cannot be legitimately. So what it comes down to is that when you have an expression 'if(x)..' and x is not numeric you already have a situation where, for the purposes of the test, x can only have two values, valid and invalid. Transforming it into 'if (x != 0)' is simply transforming it into 'if (boolean != false)'. Would you say 'if ( (x==y) == true)'? On the other hand, testing whether a numeric expression is 0 is bad practice precisely because 0 is not an invalid number. I.e. when I say 'if (x) ' and x is a pointer variable, I am testing whether x is valid as a pointer whereas when I say 'if (x)' and x is a number I am really testing whether x!=0 rather whether x is a valid number. In such cases the code would be distorting the meaning of the conditional. -- Richard Harter, Software Maintenance and Development Systems, Inc. Net address: jjmhome!smds!rh Phone: 508-369-7398 US Mail: SMDS Inc., PO Box 555, Concord MA 01742 This sentence no verb. This sentence short. This signature done.
scc@rlgvax.Reston.ICL.COM (Stephen Carlson) (03/27/91)
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 |
les@chinet.chi.il.us (Leslie Mikesell) (03/27/91)
In article <925@isgtec.UUCP> robert@isgtec.UUCP writes: >|> a) while (*foo++ = *bar++) >|> b) while (*foo ++ == *bar++) >|> c) while ((*foo++ = *bar++) != 0) >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. If you assume that the programmer didn't make a mistake (i.e. typed what he was thinking), then a) is just as obvious as c). If you assume that he did make a mistake, then c) is probably more likely to be wrong that a). More characters = more chances to screw up. Les Mikesell les@chinet.chi.il.us
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (03/27/91)
In article <1991Mar26.180311.29125@rlgvax.Reston.ICL.COM> scc@rlgvax.OPCR.ICL.COM (Stephen Carlson) writes: > while (*s++ == *t++) > ; > is not well set up to compare two arrays. Actually, sentinels are among the fastest ways to do a linear search without wasting noticeable extra space. > Statement (b) is suspicious, rare, and useless. You are exaggerating. ---Dan
scs@adam.mit.edu (Steve Summit) (03/27/91)
In article <1991Mar26.180311.29125@rlgvax.Reston.ICL.COM> scc@rlgvax.OPCR.ICL.COM (Stephen Carlson) writes: >The statement: > > while (*s++ = *t++) > ; > >is a standard C idiom... Any programmer that does not >immediately understand this cannot be called a C programmer. your absulootely write. if yu cann reed it, wye wurry abowt hou its ritten? eye cant spel wurth a dam, but aniewun that duzzent immeediyateley unnerstand mhy righting canot bee caled an englisk speekur. Steev Sumitt scs@adam.mit.edu
bhoughto@hopi.intel.com (Blair P. Houghton) (03/27/91)
In article <20107@alice.att.com> ark@alice.UUCP () writes: >In article <3182@inews.intel.com> bhoughto@pima.intel.com (Blair P. Houghton) writes: >> Put [comments] in, and make >> them accurate, and it doesn't matter how much the code obfuscates. ^^^^^^^^ I said accurate. I'm sure I did. >Not everyone agrees that comments should explain what code does >on a line-by-line level. That depends (not the agreeing; the line-by-line-ness). If it's a yacc source (the .y file), every line gets a comment, since there's often little else in the structure to indicate what j.random.variable means, when it's stuffed in an action. Comments shouldn't be things like /* * fleem the list */ /* assign a to be and check against zero */ if ( a=b )... /* nonzero; loop */ for( c = b; c; c = c->next ) b = fleem(c); /* fleem until charged */ else /* zero */ ... They should be things like /* * fleem the list */ /* keep a pointer to the head of the list for fleem() to use */ if ( a = b ) /* the head of the list exists; look for the tail */ for( c = b; c; c = c->next ) b = fleem(); /* fleem until charged */ else /* no head; start a list */ ... whereas /* * fleem the list */ if ( (a=b) != 0 ) for( c = b; c != 0; c = c->next ) b = fleem(c); /* fleem until charged */ else ... Doesn't tell me the first thing about the use of a. >The trouble is that if a comment restates >what an obvious piece of code does, then it's just clutter -- and >if it says something different from the code then something is >seriously wrong. And if the code is a collection of identifiers and operators, the comments can't help saying something different. Since nobody I know of, except device-driver writers (and maybe Chris Torek) thinks in terms of bytes and pointers (it's objects and references to the real world, even if people tend to use the terms "bytes" and "pointers", which are metaphorical terms they generally do not understand the true meaning of), every token in a piece of non-systems code has a semantic meaning far above its syntactic effects. >People bring me a lot of broken programs to help fix. The first >thing I do when looking at such a program is to cover up the >comments and insist that the author not attempt to explain the >program to me. All too often the bug has been that the code >misstated the author's intent, although that intent was correctly >stated in the comments. That can be done no matter how clearly the code states intent, as well. It's called stupidity, and no amount of adherence to the style guide will save you from it. >Stragetic comments are extremely important: ``this section ensures >that database X reflects the changes made to database Y.'' Tactical >comments, however, are sometimes of negative worth. > >As to the original question, I stand by the recommendation I >made in `C Traps and Pitfalls:' if you have an assignment as >the top-level operator in a test, such as if(a=b), rewriting it >as if((a=b)!=0) will make your intentions obvious in a way that >the original never will. My intentions are always obvious. If I put two of these: `=', it's a relational operator; if I put one, it's an assignment. If I meant something other than what I typed, it's a bug. So is: /* * fleem the list */ if ( (c=b) != 0 ) for( a = b; a != 0; a = a->next ) b = fleem(a); /* fleem until charged */ else ... Big help, those zeroes... --Blair "Just today someone showed me '{static int foo=0; ... if (foo=0)...}' and I needed neither a comment nor the lack of a '!=0' to tell me what was wrong, two seconds after it hit the screen..."
bhoughto@hopi.intel.com (Blair P. Houghton) (03/27/91)
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. I was considering this just this morning, and came to the conclusion that (1) any maintainer that dumb still has no clue about b); and, (2) a lot of repetitive stylistics become mechanized, and it's easy to type that != 0 when you don't really mean it, at 4:30am, when you're down to chewing the styrofoam cup from your last cup of coffee... So in the first case it's only half a fix (properly glued-down comments are whole and beautiful), and in the second it's seven extra characters waiting for lint2000(1) to grok their precisely _intended_ place in the universe. I have new lollipops screen-printed with calligraphic images of c) for those humans who are also waiting for such a lint... --Blair "Ahh, 4:30am. It's traditionally when most fortuitous errors occur..."
bhoughto@hopi.intel.com (Blair P. Houghton) (03/27/91)
In article <925@isgtec.UUCP> robert@isgtec.UUCP writes: >In article <355@smds.UUCP>, rh@smds.UUCP (Richard Harter) writes: >|> 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). Did I mention that I also think that accepting stylistic advice from someone who shuns whitespace in news postings is like, well, accepting candy from guys who write VLSI software... --Blair "Lots of lollipops for really BIG cheeses, this past week..."
bhoughto@hopi.intel.com (Blair P. Houghton) (03/27/91)
In article <1991Mar22.195200.11719@dg-rtp.dg.com> hagins@gamecock.rtp.dg.com (Jody Hagins) writes: >In article <3182@inews.intel.com>, bhoughto@pima.intel.com (Blair P. Houghton) writes: >|> It's called top-down design, and involves _thinking_ before >|> you start making mistakes. > >You know, I used to think this way too, while I was still an amateur. Junior, there was a time when a loose characterization like that would've met with the rending of your terminal screen. (Check with anyone in talk.politics.misc, alt.flame, or talk.bizarre, if you need a suitable strain-guage.) But now I'm just a tired, old man trying to teach people to say what they mean, mean what they say, and avoid making the rest of us have to wade through their half-assed, no-value-added attempts at self-documenting code. --Blair "Besides, another thousand lines by Friday morning and I'll earn me a bonus the size of your mortgage. When was the last time DG handed you anything other than a Christmas Turkey?"
bhoughto@hopi.intel.com (Blair P. Houghton) (03/27/91)
In article <1991Mar27.022120.29773@athena.mit.edu> scs@adam.mit.edu writes: >aniewun that duzzent >immeediyateley unnerstand mhy righting canot bee caled an englisk >speekur. Lame. Besides, considering the rampant proliferation of coding cultures out there, it's exceedingly bad for your self-preservation either to denigrate anyone for how they code, as well as to be unable to understand it no matter its form. I've had to add significant pieces of code to programs that had four previous authors, all of whom had different styles (though sufficiently close to the house-style not to get returned for revision) and worked on four different paradigms of the program. Try making semantic-, syntactic-, _and_ data-style change four times a day, then come back and tell me if yours is the One True Way. Spelling don't count for shit when the spec says "Adjust program A to learn formatting spec B to turn file format C into machine control D with operator twiddling E, and do it by yesterday," and nobody believes that more than the guy who had this job just before you got it. I.e., I may say I prefer to leave out the '!=0', but I'll bet you I can egrep(1) it more than once out of my own code from the past six months, along with a passel of cast NULLs and other syntax-denials. --Blair "I still gots lots o' lollipops. There's a significant portion of you boys and girls who aren't fessing up to your misconceptions..."
scc@rlgvax.Reston.ICL.COM (Stephen Carlson) (03/28/91)
In article <7318:Mar2622:58:0391@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: >In article <1991Mar26.180311.29125@rlgvax.Reston.ICL.COM> scc@rlgvax.OPCR.ICL.COM (Stephen Carlson) writes: >> while (*s++ == *t++) >> ; >> is not well set up to compare two arrays. > >Actually, sentinels are among the fastest ways to do a linear search >without wasting noticeable extra space. If you had quoted the entire context, you would have read: | 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. My point was that that particular encoding is not well set up even for sentinel searches. The post-loop pointers need to be readjusted. This code, for example, does not suffer that disadvantage: while (*s == *t) s++, t++; After the loop, the pointers are pointing at the unequal elements, not one past the unequal elements--which may even end up past the array bounds! Your general point about sentinels is correct, of course. -- 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 |
dak@sq.sq.com (David A Keldsen) (03/28/91)
>In article <13603@helios.TAMU.EDU> byron@archone.tamu.edu (Byron Rakitzis) writes: >>a) while (*foo++ = *bar++) >>b) while ((*foo++ = *bar++) != 0) >> >>All I can say is, if you code in style (a) rather than style (b), don't >>expect anyone reading your code to enjoy the experience. >> >>Henry, are you behind me on this one? ... henry@zoo.toronto.edu (Henry Spencer) writes: >Yes. Deliberately using a construct that looks like a well-known and subtle >programming error is a mistake. Your successor, reading your code, should >*never* have to ask himself "is this really right?"; if there is reason for >doubt, either comment the code or change it. I agree with the principle, but I disagree that it applies here. The programmer must balance clarity-by-standard-idiom and clarity-by-explicitness. From K&R1 (p. 101): ... while (*s++ = *t++) ... "Although this may seem cryptic at first sight, the notational convenience is considerable, and the idiom should be mastered, if for no other reason than that you will see it frequently in C programs." I find the idiomatic usage to be clearer, because it is easier to recognize. Dak -- David A. 'Dak' Keldsen of SoftQuad, Inc. email: dak@sq.com phone: 416-963-8337 "Perhaps the most universally recognized tool for improving a professional programmer's productivity is C. Not the C language...but the C additive, Caffeine." -- "COMPUTER LANGUAGE" April 1989 Product Wrap-Up Column by Ted Bahr
hagins@gamecock.rtp.dg.com (Jody Hagins) (03/28/91)
The discussion does not focus on whether or not you should always test against 0, but that you SHOULD always include an explicit test if using assignments. This removes all ambiguity in the conditional test. That way, you ALWAYS know that the programmer didn't put '=' when (s)he meant '==' -- Jody Hagins hagins@gamecock.rtp.dg.com Data General Corp. 62 Alexander Dr. RTP, N.C. 27709 (919) 248-6035 Nothing I ever say reflects the opinions of DGC.
scs@adam.mit.edu (Steve Summit) (03/28/91)
In article <1991Mar27.184833.7914@sq.sq.com> dak@sq.sq.com (David A Keldsen) writes: >henry@zoo.toronto.edu (Henry Spencer) writes: >>Deliberately using a construct that looks like a well-known and subtle >>programming error is a mistake. Your successor, reading your code, should >>*never* have to ask himself "is this really right?" > >I agree with the principle, but I disagree that it applies here. The >programmer must balance clarity-by-standard-idiom and clarity-by-explicitness. > >From K&R1 (p. 101): > ... > while (*s++ = *t++) > ... > >"Although this may seem cryptic at first sight, the notational convenience >is considerable, and the idiom should be mastered, if for no other reason >than that you will see it frequently in C programs." > >I find the idiomatic usage to be clearer, because it is easier to recognize. I'm sure that many of us who recommend explicit tests are aware of the cited example in K&R. Note that _use_ of the idiom is not condoned, other than obliquely through the undefined concept "notational convenience." K&R1 is one of the best programming texts it has ever been my pleasure to learn from, but it is not perfect. I have precisely one real complaint with it, namely the above-quoted example. Mere mention in K&R does not automatically render a concept inviolate; we're all allowed to think about these things for ourselves. Clearly, though, this is a religious argument. Steve Summit scs@adam.mit.edu
KKEYTE@ESOC.BITNET (Karl Keyte) (03/28/91)
I think we're back to the pretty coding argument. Yes,
while (*s++ = *t++)
;
is legal. So is
if (s = t) {
} /* Though many compilers will warn this one */
Also,
float (*(*(****(*(*myfunc())())"5")())())()
is quite legal when one wants to declare a function 'myfunc' as one returning
a pointer to function returning a pointer to an array of 5 pointers to a
pointer to a pointer to a pointer to a function returning a pointer to a
function returning a pointer to a function returning float
It's all about personal taste and a lot of sense.
Karl
s64421@zeus.usq.EDU.AU (house ron) (03/28/91)
dak@sq.sq.com (David A Keldsen) writes: >I agree with the principle, but I disagree that it applies here. The >programmer must balance clarity-by-standard-idiom and clarity-by-explicitness. >From K&R1 (p. 101): > ... > while (*s++ = *t++) > ... >"Although this may seem cryptic at first sight, the notational convenience >is considerable, and the idiom should be mastered, if for no other reason >than that you will see it frequently in C programs." Of course, K&R are not infallible. Let's argue on logic and evidence rather than on quotes from AUTHORITY. -- Regards, Ron House. (s64421@zeus.usq.edu.au) (By post: Info Tech, U.C.S.Q. Toowoomba. Australia. 4350)
torek@elf.ee.lbl.gov (Chris Torek) (03/29/91)
[`Hey Rocky, watch me pull just one more point out of my hat' `That trick NEVER works!' `This time for sure'] >>> a) while (*foo++ = *bar++) >>> b) while (*foo ++ == *bar++) >>> c) while ((*foo++ = *bar++) != 0) >In article <925@isgtec.UUCP> robert@isgtec.UUCP writes: >>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. As we all know by now, I happen to agree with this sentiment, but much more so when applied to `if'; `while' errors of this sort are less common. The following `just one more point' explains why. In article <1991Mar26.184245.3538@chinet.chi.il.us> les@chinet.chi.il.us (Leslie Mikesell) writes: >If you assume that the programmer didn't make a mistake (i.e. typed >what he was thinking), then a) is just as obvious as c). If you >assume that he did make a mistake, then c) is probably more likely >to be wrong that a). More characters = more chances to screw up. This would be true but for the fact that coding is done by *people*. Human error rate is a `jittery' function. Although a number of studies have shown remarkable consistency in the error rate measured as `number of errors found divided by number of source lines', it is also the case that people use more care with `complicated' constructs. That is, people are more likely to leave an uncorrected error behind when typing The quick brown fox jumps over the lazy dog than when typing 2.718281828459045235360 I spent more time checking the above expansion of `e' than I did typing this entire sentence. Note also that, in addition to the fact that error rate is not a monotonic function of `number of characters typed', error studies typically find different `kinds' of errors. One important kind of error is the `typo' (typographical error) (and this one really *is* a function of the number and placement of characters typed). Typographial errors take three forms: transpositions (`The quick bronw fox jumps over hte lazy dog') insertions (`The quiick brown fox jumpsd over the lazy dog') deletions (`The quick brown fox umps over the lazy dog') Typographical errors are, if not the most common form of error, certainly in the top contenders. Keeping these in mind, let us consider C code. After one becomes familiar with C, constructs like if ((c = getchar()) != EOF) become `natural' and one does not think twice when writing them. In many languages (not just C, although C is rare in its partcular spelling) constructs like if (a == b) are also `natural' and again one does not think twice. Now, most errors can be caught before they happen, just by thinking twice. So if people found if (a == b) unfamiliar, they would check again and possibly discover that they had, by mistake, typed in if (a = b) ---but `if (a == b)' is too familiar to bother rechecking, and such typos go unnoticed. Thus, when I (as a software maintainer) find if (a = b) I must consider this a `red flag' signifying a possible error, while if ((a = b) != 0) is quite unlikely to be a typo. On the other hand, while loops of the form while (*a++ == *b++) are considerably more rare. It is therefore more likely that whoever wrote while (*a++ = *b++) really intended the assignment. Still, deletions are a common form of typographical error; perhaps the single `=' is a mistake anyway. If the assignment is intended, while ((*a++ = *b++) != 0) is a clear flag that `there is no deletion typo here'. If the latter is what was meant but while ((*a++ == *b++) != 0) actually appears, this acts as another flag: it is unusal for people to use the result of a comparsion in anything but a `direct boolean' context (if, while, &&, etc.). In other words, it all comes down to these facts: * Embedded assign-and-test is common enough not to get rechecked. * Typographic errors of deletion and of doubling (`quiick') are very common. Combining these leads to the two mistakes below: if (a = b) /* oops */ foo(); while (n < lim) n == f(n); /* oops */ both of which draw warnings from many compilers. -- In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427) Berkeley, CA Domain: torek@ee.lbl.gov
asd@cbnewsj.att.com (Adam S. Denton) (03/29/91)
In article <1991Mar27.184833.7914@sq.sq.com> dak@sq.sq.com (David A Keldsen) writes: > >>In article <13603@helios.TAMU.EDU> byron@archone.tamu.edu (Byron Rakitzis) writes: >>Yes. Deliberately using a construct that looks like a well-known and subtle >>programming error is a mistake. Your successor, reading your code, should >>*never* have to ask himself "is this really right?"; if there is reason for >>doubt, either comment the code or change it. > >I agree with the principle, but I disagree that it applies here. The >programmer must balance clarity-by-standard-idiom and clarity-by-explicitness. > >From K&R1 (p. 101): > ... > while (*s++ = *t++) > ... > >"Although this may seem cryptic at first sight, the notational convenience >is considerable, and the idiom should be mastered, if for no other reason >than that you will see it frequently in C programs." > >I find the idiomatic usage to be clearer, because it is easier to recognize. Although K&R was the original, and the 2nd edition is exemplary, there are two areas in the original that I have come to disagree with (and I think others in this forum have too): 1) The construct you cite above, and 2) The `hint' that pointers have anything AT ALL to do with integers I disagree with K&R on both these points. "while (a++ = b++)" might be cute, but it is truly annoying to have to sift through the code to determine if it's a bug or not. Especially since the != 0 test could just have easily been included, effectively removing all ambiguity and with no run-time penalty (as others have pointed out) and with no howl from lint as an added bonus. The second construct is dealt with in the FAQ, but I still see this misuse in even "modern" code -- consider the following code, which is ubiquitous in MSDOS: (my apologies for including platform-specific code here) void far *p; ... p = (void far *) 0xFFFFE000; when IMHO the proper abstraction should be void far *p; ... p = MK_FP(0xFFFFu, 0xE000u); as the latter does not include an integer-to-pointer conversion, and I would hold that it is more portable (most MSDOS compilers include the MK_FP macro FOR PRECISELY the purpose of avoiding an integer-to-pointer conversion). This topic touches on issues of proper data abstraction and typing which are not discussed sufficiently in most C books. That may be why there is such a debate, and why code like the former above continues to be written. Happy coding, Adam Denton asd@mtqua.att.com
oz@yunexus.yorku.ca (Ozan Yigit) (03/29/91)
In article <1991Mar27.184833.7914@sq.sq.com> dak@sq.sq.com (David A Keldsen) writes: >I find the idiomatic usage to be clearer, because it is easier to recognize. This I suspect, is crucial to the debate: Idioms are a part of most languages (are there any without them?), and they remain as idioms exactly because they are used frequently and well understood as a unit. C idioms are no exception. oz --- In seeking the unattainable, simplicity | Internet: oz@nexus.yorku.ca only gets in the way. -- Alan J. Perlis | Uucp: utai/utzoo!yunexus!oz
cdm@gem-hy.Inel.GOV (Dale Cook) (03/29/91)
In article <1991Mar26.184245.3538@chinet.chi.il.us>, les@chinet.chi.il.us (Leslie Mikesell) writes: |> In article <925@isgtec.UUCP> robert@isgtec.UUCP writes: |> >|> a) while (*foo++ = *bar++) |> >|> b) while (*foo ++ == *bar++) |> >|> c) while ((*foo++ = *bar++) != 0) |> |> >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. |> |> If you assume that the programmer didn't make a mistake (i.e. typed |> what he was thinking), then a) is just as obvious as c). If you |> assume that he did make a mistake, then c) is probably more likely |> to be wrong that a). More characters = more chances to screw up. ^ Don't you mean '==' ?? ---------------------------------------------------------------------- --- Dale Cook "You can sum this game up in one word - cdm@inel.gov 'you never know'". --- J. Andujar The opinions are mine. The following disclaimer is my employers. ---------------------------------------------------------------------- ========== long legal disclaimer follows, press n to skip =========== Neither the United States Government or the Idaho National Engineering Laboratory or any of their employees, makes any warranty, whatsoever, implied, or assumes any legal liability or responsibility regarding any information, disclosed, or represents that its use would not infringe privately owned rights. No specific reference constitutes or implies endorsement, recommendation, or favoring by the United States Government or the Idaho National Engineering Laboratory. The views and opinions expressed herein do not necessarily reflect those of the United States Government or the Idaho National Engineering Laboratory, and shall not be used for advertising or product endorsement purposes.
scs@adam.mit.edu (Steve Summit) (03/29/91)
In articles too numerous to mention, people are asserting that
while(*a++ = *b++)
is or is not good style. At this point neither side is likely to
convince the other.
If you like
while(*a++ = *b++)
keep on using it. Neither I nor any other Usenet poster is going
to (or can) stop you.
If you prefer
while((*a++ = *b++) != 0)
more power to you, and keep on using it.
If you're undecided, don't let the assertions being made ("THIS
is good style, and I have Spoken") sway you unnecessarily.
Decide for yourself which is clearer and least likely to be
misunderstood by future maintainers. Whichever way you choose,
you've got precedents -- there is obviously no consensus on which
way is "best."
A colleague of mine once expressed a bit of dismay that he'd
never be a "good" C programmer, because he couldn't write, and
didn't feel like learning how to write, the supercompressed code
he saw all around him. He was writing perfectly good code, but
he was tending to leave things explicit and obvious. It is a sad
commentary on our little subprofession that barely-penetrable
code is so widespread that it can be perceived as a requirement.
Codesmanship (or, job security through obscurity) is alive and
well.
Steve Summit
scs@adam.mit.edu
bhoughto@hopi.intel.com (Blair P. Houghton) (03/29/91)
In article <11563@dog.ee.lbl.gov> torek@elf.ee.lbl.gov (Chris Torek) writes: >function of the number and placement of characters typed). Typographial >errors take three forms: > > transpositions (`The quick bronw fox jumps over hte lazy dog') > insertions (`The quiick brown fox jumpsd over the lazy dog') > deletions (`The quick brown fox umps over the lazy dog') replacements (`The quick brown fox jumps ovwr the lazy dog') >Keeping these in mind, let us consider C code. Consideration noted. When dealing with ~45,000 lines of code (it's over there, on the Apollo, compiling...) I don't bother with statistics; I use egrep. Just tonight, in fact, I found a `==' that had accidentally been typed as `=', just by typing egrep 'display[ ]*=' *.[ch] Thirty seconds from suspicion to fix, and I didn't have to go looking for `!=0' to do it... >I must consider this a `red flag' signifying a possible error, while > > if ((a = b) != 0) It's still nothing more than redundant. Where's the explanation? I still don't know what a and b are doing in that conditional in the first place. I'd really rather see a comment that mentions that this is an assignment that tests, plus what's being assigned and tested, than that contentless, crufty, explicit comparison with zero. I have a key on my vt220 programmed with a vi(1) macro (and labeled in pencil) which echoes thusly: oif ()^M^T/* true */^[k$i and when in vi types (here, I'll do it now):<shift><F13> if (and I start typing here) /* true */ So the first thing ever I see after typing the expression is that the next line wants a comment, and the first thing I type in that comment is what "true" means, like if ( a = b ) /* a and b are non-null; list b exists; append to list */ a->next = ... I couldn't care less whether the equals was right; all it tells me is _how_ you chose the true path; if I can't tell _why_ you chose it I'll dress you down in a hurry. if I _can_ tell why you chose it I can tell you the optimal way to choose it and how you nearly optimal is your method of choosing. (This one isn't on its face; it should be if ( b ) /* b non-null; list exists; copy holder and append dingus */ a = b; a->next = ... So the next question to ask is, Did I need `a' later regardless of the test? Hey! Look! Context-sensitivity! Who would've thunk it?) > * Embedded assign-and-test is common enough not to get rechecked. It is by any experienced maintainer. Take, egrep '\([^!(=]*=[^=)]*\)' *.[ch] for instance. Running this on ~/src/*.[ch] produced: loghist.c: for ( i = 0; i < n_slots; i++ ) rna.c:#define hour(x) ( ((x)<=0||(x)>=24) ? 12 : ( (x)>12 ? (x)-12 : (x) ) ) rna.c: if ( (af = fopen(accf,"r")) == NULL ) { rna.c: if ( tms->tm_hour >= a->onhr && tms->tm_hour < a->offhr ) { toupper.c: while ( (int) (c = getchar()) != EOF ) udkeys.c: if ( (n = atoi ( s+1 )) > 5 && n < 20 ) Lookitthat. 5000 lines of code produce exactly three assign-and-tests, and one of them is a test against -1, while another is tested against 5, and one is testing fopen() to see if it _is_ NULL... Seems it isn't all that common, after all, even among those of us who tend to use such things blithely... (Some pretty cool tools there, btw... rna, in fact -- and you'll find this _really_ hard to believe -- prevents me from running rn during work hours... :-) It works, too. I see that polite "You are prohibited..." message and I just clear the screen and go back to crashing my Apollo...) > if (a = b) /* oops */ > n == f(n); /* oops */ > >both of which draw warnings from many compilers. And a few hundred comp.lang.c readers, it seems... --Blair "C'mon, machine, link those puppies!"
bhoughto@hopi.intel.com (Blair P. Houghton) (03/29/91)
In article <22167@yunexus.YorkU.CA> oz@yunexus.yorku.ca (Ozan Yigit) writes: >This I suspect, is crucial to the debate: Idioms are a part of most >languages (are there any without them?), Yeah: Fortran. Just try stuttering a comma, sometime... >and they remain as idioms exactly >because they are used frequently and well understood as a unit. C idioms >are no exception. 23-Skiddoo, eh? --Blair "Hey-nonny-nonny and a hot-cha-cha, sirrah." P.S. Don't forget to grok the Summary: line, y'all.
gwyn@smoke.brl.mil (Doug Gwyn) (03/30/91)
In article <3555@inews.intel.com> bhoughto@hopi.intel.com (Blair P. Houghton) writes: >toupper.c: while ( (int) (c = getchar()) != EOF ) I hope you noticed that there is a bug there.
rsalz@bbn.com (Rich Salz) (03/31/91)
In <3555@inews.intel.com> bhoughto@hopi.intel.com (Blair P. Houghton) writes: >toupper.c: while ( (int) (c = getchar()) != EOF ) The cast implies that c is char. If so, this line is buggy. -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.
dak@sq.sq.com (David A Keldsen) (03/31/91)
I wrote: >>I agree with the principle, but I disagree that it applies here. The >>programmer must balance clarity-by-standard-idiom and clarity-by- >>explicitness. >>From K&R1 (p. 101): >> ... >> while (*s++ = *t++) >> ... >>"Although this may seem cryptic at first sight, the notational convenience >>is considerable, and the idiom should be mastered, if for no other reason >>than that you will see it frequently in C programs." s64421@zeus.usq.EDU.AU (house ron) writes: >Of course, K&R are not infallible. Let's argue on logic and evidence >rather than on quotes from AUTHORITY. Seems to me that there is a great deal of evidence there. You *will* see this construct frequently if you are looking at other people's code. And the line which you did *not* include, which was my commentary on the quote: >>I find the idiomatic usage to be clearer, because it is easier to recognize. is hardly an argument from authority. I find the use of the idiom clearer, when it is *simple* and *concise*. When the algorithm departs from the idiom, *then* use explicit tests! In another article, Steve Summit writes: > I'm sure that many of us who recommend explicit tests are aware > of the cited example in K&R. Note that _use_ of the idiom is not > condoned, other than obliquely through the undefined concept > "notational convenience." As I've emphasized above, I think that explicit tests are a *very* good idea when the code isn't simple and clear. However, I find that that "always use explicit tests" sometimes leads to unclear code, because it is no longer concise, and I have to figure out, "now, why is the writer emphasizing the comparison? What is tricky here?" Consider the same argument for the increment operator. Increment is useful (IMHO) because it makes the use of a common programming idiom *very* clear. > K&R1 is one of the best programming texts it has ever been my > pleasure to learn from, but it is not perfect. I have precisely > one real complaint with it, namely the above-quoted example. > Mere mention in K&R does not automatically render a concept > inviolate; we're all allowed to think about these things for > ourselves. Absolutely. > Clearly, though, this is a religious argument. Yes, it's certainly about difficult to dispute preferences. Shall we discuss the One True Bracing Style? ;-) Dak -- David A. 'Dak' Keldsen of SoftQuad, Inc. email: dak@sq.com phone: 416-963-8337 "You can draw something besides tigers, can't you?" "Sure, leopards, pumas, ocelots.. ..you name it." -- Calvin and Hobbes
lamont@uts.amdahl.com (Duane Richard LaMont) (03/31/91)
In article <15634@smoke.brl.mil> Doug Gwyn writes: >>toupper.c: while ( (int) (c = getchar()) != EOF ) > >I hope you noticed that there is a bug there. I give up. What's the bug? I gave it the benefit of the doubt and assumed that 'c' was already an int and that the cast was redundant. Rick LaMont
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (04/01/91)
In article <3465@litchi.bbn.com> rsalz@bbn.com (Rich Salz) writes: > In <3555@inews.intel.com> bhoughto@hopi.intel.com (Blair P. Houghton) writes: > >toupper.c: while ( (int) (c = getchar()) != EOF ) > The cast implies that c is char. If so, this line is buggy. Maybe it's long? :-) ---Dan
hamish@mate.sybase.com (Just Another Deckchair on the Titanic) (04/03/91)
In article <3425@inews.intel.com> bhoughto@nevin.intel.com (Blair P. Houghton) writes: > [...] >Hey, the real world encroaches. I simply consider > > /* assign-cum-check */ > if ( a=b ) > >more expressive, readable, correct, and professional than > > if ( (a=b) != 0 ) > Ah, this from a man who flamed me for daring to introduce the notion of formal semantics into a discussion on compiler writing and formal machine translation to help sort out a problem he had with C semantics.... Blair dearest - do you still consider your earnest proposal to add the addition of two pointers to C standards to be correct and professional? And your ill-tempered, ignorant and hilariously bad flamage based on mis-reading and mis-attributing postings? Well, it was fun while it lasted. The Real World encroaches. It's still sorta hard for *this* long-memoried Pointer Fairy to take you seriously.... In the above example, your opinion is no more Real World (you worldly thing, you) than than it was then. As to "professional" - who's kidding who? Started working on multiplying two pointers together yet? Submitted it to the Ansi committee? Understood the role of formal semantics in compiler writing yet? Hamish ---------------------------------------------------------------------------- Hamish Reid Sybase Inc, 6475 Christie Ave, Emeryville CA 94608 USA +1 415 596-3917 hamish@sybase.com ...!{mtxinu,sun}!sybase!hamish
bhoughto@nevin.intel.com (Blair P. Houghton) (04/04/91)
In article <29444:Mar3120:23:3491@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: >In article <3465@litchi.bbn.com> rsalz@bbn.com (Rich Salz) writes: >> In <3555@inews.intel.com> bhoughto@hopi.intel.com (Blair P. Houghton) writes: >> >toupper.c: while ( (int) (c = getchar()) != EOF ) >> The cast implies that c is char. If so, this line is buggy. > >Maybe it's long? :-) No, actually it's a quad double pointer to a function returning a far union of wchar_t and an odd-length bit field. It's also several years old and the cast was inserted to shut lint up, not to fix the bad conversion, which deserves while ( ( c = (char) getchar() ) != (char)EOF ) or, if you prefer, int i; while ( ( i = getchar() ) != EOF ) c = (char)i; --Blair "Call For Votes: comp.lang.c.kludges.just.to.shut.lint.up"
bhoughto@nevin.intel.com (Blair P. Houghton) (04/04/91)
In article <12269@sybase.sybase.com> hamish@mate.sybase.com (Just Another Deckchair on the Titanic) writes: >In article <3425@inews.intel.com> bhoughto@nevin.intel.com (Blair P. Houghton) writes: >>Hey, the real world encroaches. I simply consider >> /* assign-cum-check */ >> if ( a=b ) >>more expressive, readable, correct, and professional than >> if ( (a=b) != 0 ) >Ah, this from a man who flamed me for daring to introduce the notion of >formal semantics into a discussion on compiler writing and formal machine >translation to help sort out a problem he had with C semantics.... I don't know what this has to do with formal semantics, Deckchair, but I do still have the notes I made on the semantic interpretation of pointer sums re operations on them (hint: it's uglier than you think, but not indescribable in human language). >And your ill-tempered, ignorant and hilariously bad >flamage based on mis-reading and mis-attributing postings? Well, it was >fun while it lasted. Shit happens, swabbie's-butt-breath. (Just doing my part to positively reinforce your opinion of me, hilariously bad as it may be.) >The Real World encroaches. It's still sorta hard for *this* >long-memoried Pointer Fairy to take you seriously.... In the above >example, your opinion is no more Real World (you worldly thing, you) >than than it was then. As to "professional" - who's kidding who? That's "whom," you North-Atlantic sucking piece of leisure furniture. (From technical spelling flames to non-technical spelling flames; oh, what a RANGE I have...) >Started working on multiplying two pointers together yet? Submitted it >to the Ansi committee? Understood the role of formal semantics in >compiler writing yet? Tell me the type of an object large enough to hold the product of two pointers and I'll work on it. And if you want a lesson in formal semantics, try writing a silicon compiler. --Blair "Until then, enjoy the fat ladies at the bottom of the sea."
gwyn@smoke.brl.mil (Doug Gwyn) (04/05/91)
In article <12269@sybase.sybase.com> hamish@mate.sybase.com (Just Another Deckchair on the Titanic) writes: >Started working on multiplying two pointers together yet? Inner, outer, or wedge product? I'm not being entirely facetious here -- one of the reasons that I'm opposed to operator overloading, for example in C++, is that there are often several reasonable distinct meanings that can be given to common algebraic operations when applied to more complex objects than real numbers. Multiplication is the most common example.
gwyn@smoke.brl.mil (Doug Gwyn) (04/05/91)
In article <3646@inews.intel.com> bhoughto@nevin.intel.com (Blair P. Houghton) writes: > while ( ( c = (char) getchar() ) != (char)EOF ) Assuming that the loop is meant to handle all possible byte values, this is also buggy.
tom@syssoft.com (Rodentia) (04/05/91)
In article <3465@litchi.bbn.com> rsalz@bbn.com (Rich Salz) writes: >In <3555@inews.intel.com> bhoughto@hopi.intel.com (Blair P. Houghton) writes: >>toupper.c: while ( (int) (c = getchar()) != EOF ) >The cast implies that c is char. If so, this line is buggy. Does this mean that there if c is char, there is no way to assign the getchar and test it for EOF without having it cast down to char? Or would "while (((int)c = getchar()) != EOF)" do it? If so, would "while ((((int)(*c++)) = getchar()) != EOF)" cause improper incrementation, access, both, or worse? -- Thomas Roden | tom@syssoft.com Systems and Software, Inc. | Voice: (714) 833-1700 x454 "If the Beagle had sailed here, Darwin would have | FAX: (714) 833-1900 come up with a different theory altogether." - me |
alan@ukpoit.co.uk (Alan Barclay) (04/05/91)
In article <91087.152922KKEYTE@ESOC.BITNET> KKEYTE@ESOC.BITNET (Karl Keyte) writes: > > float (*(*(****(*(*myfunc())())"5")())())() > >is quite legal when one wants to declare a function 'myfunc' as one returning >a pointer to function returning a pointer to an array of 5 pointers to a >pointer to a pointer to a pointer to a function returning a pointer to a >function returning a pointer to a function returning float > no it isn't, presuming that the "5" is a typo for [5], then your declaration is float (*(*(****(*(*myfunc())())[5])())())(), which according to dcl, as found in K&R2 is myfunc: function returning pointer to function returning pointer to array[5] of pointer to pointer to pointer to pointer to function returning pointer to function returning pointer to function returning float I.E, where you have three "pointer to", in sucession you should have four.
volpe@camelback.crd.ge.com (Christopher R Volpe) (04/08/91)
In article <1991Apr4.215605.2801@syssoft.com>, tom@syssoft.com (Rodentia) writes: |>In article <3465@litchi.bbn.com> rsalz@bbn.com (Rich Salz) writes: |>>In <3555@inews.intel.com> bhoughto@hopi.intel.com (Blair P. Houghton) writes: |>>>toupper.c: while ( (int) (c = getchar()) != EOF ) |>>The cast implies that c is char. If so, this line is buggy. |> |>Does this mean that there if c is char, there is no way to assign the |>getchar and test it for EOF without having it cast down to char? c simply shouldn't be a char. It should be an int, since that is what getchar returns. getchar can't return a char because it has to return 257 distinct values: all 256 values of char, plus the value EOF. Write it like this: int c; ... while ((c=getchar()) != EOF) {...}; |>Thomas Roden | tom@syssoft.com |>Systems and Software, Inc. | Voice: (714) 833-1700 x454 |>"If the Beagle had sailed here, Darwin would have | FAX: (714) 833-1900 |>come up with a different theory altogether." - me | ================== Chris Volpe G.E. Corporate R&D volpecr@crd.ge.com
hamish@mate.sybase.com (Just Another Deckchair on the Titanic) (04/09/91)
In article <3647@inews.intel.com> bhoughto@nevin.intel.com (Blair P. Houghton) writes: >In article <12269@sybase.sybase.com> hamish@mate.sybase.com (Just Another Deckchair on the Titanic) writes: <>In article <3425@inews.intel.com> bhoughto@nevin.intel.com (Blair P. Houghton) writes: >>>Hey, the real world encroaches. I simply consider <>> /* assign-cum-check */ >>> if ( a=b ) <>>more expressive, readable, correct, and professional than >>> if ( (a=b) != 0 ) <>Ah, this from a man who flamed me for daring to introduce the notion of >>formal semantics into a discussion on compiler writing and formal machine <>translation to help sort out a problem he had with C semantics.... > <I don't know what this has to do with formal semantics, Deckchair, >but I do still have the notes I made on the semantic interpretation <of pointer sums re operations on them (hint: it's uglier than you >think, but not indescribable in human language). < >>And your ill-tempered, ignorant and hilariously bad <>flamage based on mis-reading and mis-attributing postings? Well, it was >>fun while it lasted. < >Shit happens, swabbie's-butt-breath. (Just doing my part <to positively reinforce your opinion of me, hilariously >bad as it may be.) For anyone out there still awake, I have taken this to email, for obvious reasons. (Anyone interested in the results (eg. the answer to such burningly relevant questions as "what did Blair see on the road to Intel that caused him to switch from flaming people for using semantics to help resolve real-world compiler writing issues, to (perhaps) seeing some use to formal semantics?", and "has Blair learnt to get attributions right yet (and not flame himself in the foot doing so..." can email me (or him)). Hamish ---------------------------------------------------------------------------- Hamish Reid Sybase Inc, 6475 Christie Ave, Emeryville CA 94608 USA +1 415 596-3917 hamish@sybase.com ...!{mtxinu,sun}!sybase!hamish