[comp.lang.c] One more point regarding = and ==

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