[net.lang.c] more questions about efficient C code

shekita@crystal.UUCP (06/21/85)

I am currently modifying C code, written by someone else,
that is incredibly terse. It's paramount that the code
be fast, so I presume the code is terse for speed. I'm
now curious about a few things:

1) Is the "var = (bool expr) ? : expr1 : expr2" construct faster
   than just a good old if statement? 

2) Are for loops faster than while loops? 

3) Is there really much to be gained by using assignment within
   a boolean expression, for example, is

	if ((fp = fopen("foo", "r") == NULL) {
		 ...
	}

   really that much faster than

	fp = fopen("foo", "r");
	if (fp == NULL) {
		...
	}

 4) Are tests for zero more efficently written as

	if (var) {
		...
	}

    rather than as

	if (var != 0) {
		...
	}

chris@umcp-cs.UUCP (Chris Torek) (06/22/85)

All of these depend on your compiler.  I'm going to answer them for
4BSD Vax PCC.

> 1) Is the "var = (bool expr) ? : expr1 : expr2" construct faster
>    than just a good old if statement? 

Depends.  PCC generates moves into r0 for expr1 and expr2, followed
by a move from r0 to var.  If var is already a register, this is
clearly slower.  If it's a complex pointer dereference, it could be
faster.

> 2) Are for loops faster than while loops? 

No.

> 3) Is there really much to be gained by using assignment within
>    a boolean expression, for example, is
>
>	if ((fp = fopen("foo", "r") == NULL) {
>
>    really that much faster than
>
>	fp = fopen("foo", "r");
>	if (fp == NULL) {

Again, depends: if "fp" is not a register, the assignment+test is faster,
since you end up branching after the assignment from r0 to "fp".  If it
is a register, it comes out the same.  (At least after optimization, usually).
The first form is never slower, anyway.

> 4) Are tests for zero more efficently written as
>
>	if (var) {
>
>    rather than as
>
>	if (var != 0) {

No.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland

jjd@wlcrjs.UUCP (Joe Durnavich) (06/25/85)

>> 3) Is there really much to be gained by using assignment within
>>    a boolean expression, for example, is
>>
>>	if ((fp = fopen("foo", "r") == NULL) {
>>
>>    really that much faster than
>>
>>	fp = fopen("foo", "r");
>>	if (fp == NULL) {
>
>Again, depends: if "fp" is not a register, the assignment+test is faster,
>since you end up branching after the assignment from r0 to "fp".  If it
>is a register, it comes out the same.  (At least after optimization, usually).
>The first form is never slower, anyway.

	This example bothers me.  I'm not sure what all makes up the
	fopen subroutine, but the addition or subtraction of one measely
	assignment statement *has* to be negligible when compared to what
	goes on in fopen.  Even if that code is in the innermost of inner
	loops, the "optimization" will still be unnoticable.  I know
	it's just an example of an assignment within a boolean expression,
	but I see a *lot* of programs with that same code.  Are we really
	gaining anything, or is it merely psychological?

					Joe Durnavich
					ihnp4!wlcrjs!jjd

No part of this message may be reproduced, stored in a retrieval system, or
transmitted, in any form or by any means, without the permission of the author.

minow@decvax.UUCP (Martin Minow) (06/26/85)

The question was asked whether the common C idiom
	if ((fp = fopen("foo.bar", "r")) == NULL) { ...
really is more efficient than
	fp = fopen("foo.bar", "r");
	if (fp == NULL) { ...

In response, Joe Durnavich makes the good point that the saving
of one measly move instruction (which a good compiler would
optimize out anyway) isn't worth the effort.

In response, I would again point out that this is a C idiom --
one of the habits a programmer picks up for better or worse.
In defense, I would note that writing this as a single statement
ties (visually) the if condition closer to the fopen() result that
is being tested than would be the case were one to write two
statements.

Martin Minow
decvax!minow

chris@umcp-cs.UUCP (Chris Torek) (06/27/85)

> This example
[ if ((fp = fopen(...)) == NULL) vs fp = fopen(...); if (fp == NULL) ]
> bothers me.  I'm not sure what all makes up the fopen subroutine,
> but the addition or subtraction of one measly assignment statement
> *has* to be negligible when compared to what goes on in fopen.
> Even if that code is in the innermost of inner loops, the "optimization"
> will still be unnoticable.  I know it's just an example of an
> assignment within a boolean expression, but I see a *lot* of programs
> with that same code.  Are we really gaining anything, or is it
> merely psychological?

Heck, 500 nanoseconds is significant, isn't it? :-)

Besides, you can save four bytes per test.  I'll bet it makes a disk
block or two of difference.  And we all need all the space we can get,
right? :-)

Seriously, the difference in the fopen call is pretty small, but
the difference in something like

	for (...)
		for (...) {
			if ((j = (k >> 2) - m) == 0)
				k++;
		}

can be important.  Once you get into the habit of testing the results
of an assignment, it doesn't even look funny anymore.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland

mhs@enmasse.UUCP (Mike Schloss) (06/27/85)

> I am currently modifying C code, written by someone else,
> that is incredibly terse. It's paramount that the code
> be fast, so I presume the code is terse for speed. I'm
> now curious about a few things:
> 
> .
> .
> .

Sorry but it all depends on your particular compiler
implementation and the machine you are running on.
There are two ways to find the answers to your questions.
One is to write a simple test program and use the '-S'
flag of the compiler.  This will produce assembly code
that you can examine and see what intructions are being
generated for any particular expression.  If you dont
want to get your hands dirty with assembler then write
your test program to run a couple 100k times though
each expression and time it.

brooks@lll-crg.ARPA (Eugene D. Brooks III) (06/28/85)

> >>	if ((fp = fopen("foo", "r") == NULL) {
> 	This example bothers me.  I'm not sure what all makes up the
> 	fopen subroutine, but the addition or subtraction of one measely
> 	assignment statement *has* to be negligible when compared to what
> 	goes on in fopen.  Even if that code is in the innermost of inner
> 	loops, the "optimization" will still be unnoticable.  I know
> 	it's just an example of an assignment within a boolean expression,
> 	but I see a *lot* of programs with that same code.  Are we really
> 	gaining anything, or is it merely psychological?

Its its not for the sake of exectution efficiency.  You see it
a lot for the sake of statement efficiency.  Its the efficient and STANDARD
way of saying it.  Any experienced C programmer recognizes this code
automatically and produces it without thinking.  You have problems with
it because you are not an experienced C programmer yet.

You of course need to include the missint paren :-)

bright@dataio.UUCP (Walter Bright) (06/28/85)

In article <474@crystal.UUCP> shekita@crystal.UUCP writes:
>I am currently modifying C code, written by someone else,
>that is incredibly terse. It's paramount that the code
>be fast, so I presume the code is terse for speed.

For every case you mentioned, I can think of different compilers
where one case is faster in one compiler and the other case is
faster for the other compiler. The only way to tell for sure for
your compiler is to examine the assembly code output.

zarth@drutx.UUCP (CovartDL) (06/28/85)

I have noticed lately that if I have the following:

		foo()
		  {
		   char c;

		   if((c = getchar()) != '\n') {
		      /* more code here */
		      }
		   }

and I do not use 'c' any where else lint complains. I get the message

		c set but no used in function foo

I tried reverseing the test as below thinking c would have to appear on the
right side of at least one test but, I get the same error.

		foo()
		  {
		   char c;

		   if('\n' != (c = getchar())) {
		      /* more code here */
		      }
		   }

Is it simply the use of the compound statement structure that causes this??
Thanks in advance for the solution.


				- Zarth Arn

ark@alice.UUCP (Andrew Koenig) (06/29/85)

> I have noticed lately that if I have the following:

> 		foo()
> 		  {
> 		   char c;
> 
> 		   if((c = getchar()) != '\n') {
> 		      /* more code here */
> 		      }
> 		   }
> 
> and I do not use 'c' any where else lint complains. I get the message
> 
> 		c set but no used in function foo

Ummm... isn't lint right?  Why couldn't you just write:

	if (getchar() != '\n') { ...

mash@mips.UUCP (John Mashey) (06/29/85)

> > >>	if ((fp = fopen("foo", "r") == NULL) {
> 
> Its its not for the sake of exectution efficiency.  You see it
> a lot for the sake of statement efficiency. ...

It is also useful for human efficiency, once you become accustomed to the
idiom.  Code must be read and understood by humans; less (signifcant, not
{}, (), etc) tokens are generally faster, within reasonable limits.
A similar example is OP= operators; i.e., x = x + 3 requires slightly
longer to read than x += 3, if only because you don't have tyo check that
the variables on the right and left are the same.  Trivial in this case,
but less so when it's  long_identifier1 += 3 instead of
long_identifier1 += long_identifier1 + 3;
No one would claim this is a big effect, but every little bit helps,
especially when it even makes life easier for the compiler.
-- 
-john mashey
UUCP: 	{decvax,ucbvax,ihnp4}!decwrl!mips!mash
DDD:  	415-960-1200
USPS: 	MIPS Computer Systems, 1330 Charleston Rd, Mtn View, CA 94043

henry@utzoo.UUCP (Henry Spencer) (06/30/85)

> Seriously, the difference in the fopen call is pretty small, but
> the difference in something like
> 
> 	for (...)
> 		for (...) {
> 			if ((j = (k >> 2) - m) == 0)
> 				k++;
> 		}
> 
> can be important.  Once you get into the habit of testing the results
> of an assignment, it doesn't even look funny anymore.

Retch.  To quote the "Indian Hill C Style" paper:

	For example, the code:
	.DS
	a = b + c;
	d = a + r;
	.DE
	should not be replaced by
	.DS
	d = (a = b + c) + r;
	.DE
	even though the latter may save one cycle.
	Note that in the long run the time difference between the two will
	decrease as the optimizer gains maturity, while the difference in
	ease of maintenance will increase as the human memory of what's
	going on in the latter piece of code begins to fade...
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

henry@utzoo.UUCP (Henry Spencer) (06/30/85)

> ...  Any experienced C programmer recognizes this code
> automatically and produces it without thinking.  You have problems with
> it because you are not an experienced C programmer yet.

Rubbish.  "Any experienced programmer should be able to understand that"
really means "we know it's hard to read, but...".  The idea is to make
life as easy as possible for the poor guy who has to maintain the stuff
next.  Note "as easy as possible", as opposed to "not quite impossible".

I've been programming in C for over a decade, by the way.
-- 
"Maturity means doing what's right, not just what's easy."

				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

quiroz@rochester.UUCP (Cesar Quiroz) (07/01/85)

From article <3136@drutx.UUCP> (version B 2.10.2 9/18/84; site rochester.UUCP version B 2.10.1 (Denver Mods 7/26/84) 6/24/83; site drutx.UUCP rochester!seismo!harvard!think!mit-eddie!genrad!decvax!harpo!whuxlm!whuxl!houxm!ihnp4!drutx!zarth zarth@drutx.UUCP (CovartDL)):
>I have noticed lately that if I have the following:
>
>		foo()
>		  {
>		   char c;
>
>		   if((c = getchar()) != '\n') {
>		      /* more code here */
>		      }
>		   }
>
>and I do not use 'c' any where else lint complains. I get the message
>
>		c set but no used in function foo
>
        . . .
>
>				- Zarth Arn

	Seems like a very desirable behavior in the part of Lint.  Either you really
need the value of c someplace else (and then your program contains a bug) or it 
could be easily simplified as:

		foo()
		  {
		   /* NOT NEEDED:  char c; */

		   if(((char) getchar()) != '\n') {
		      /* more code here */
		      }
		   }


	Or something similar that doesn't keep the value of getchar() in a useless 
variable.  At any rate, be sure you really don't need it!

Cesar

chris@umcp-cs.UUCP (Chris Torek) (07/02/85)

There is actually a difference between

	char c;

	while ((c = getchar()) != '\n')

and

	while (getchar() != '\n')

The latter expression compares the return value of getchar() (an
int) with '\n' (another int).  The former compares the value of
the assignment "c = getchar()" (a char) with an int.  Lint is
arguably correct in complaining, as "c" itself is not actually used
in the comparison, but it does have an effect.

By the way, the former section of code is technically incorrect:
getchar returns an int, since EOF is supposed to be something that
is not valid as a char.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland

chris@umcp-cs.UUCP (Chris Torek) (07/02/85)

>>[...] it all depends on your particular compiler
>>implementation [...] use the '-S' flag of the compiler
>>[to] produce assembly code that you can examine [...].

>Unfortunately, this option is not likely to show you the
>optimized code you would get from running the compiler with
>the -O flag.  To really see what's being generated, compile
>it, and then look at the object file with something like
>foo,24?ai
>in adb.

That's not necessary; -O and -S work just fine together, at
least under 4BSD (including Sun 4.2).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland

mhs@enmasse.UUCP (Mike Schloss) (07/02/85)

> I have noticed lately that if I have the following:
> 
> 		foo()
> 		  {
> 		   char c;
> 
> 		   if((c = getchar()) != '\n') {
> 		      /* more code here */
> 		      }
> 		   }
> 
> and I do not use 'c' any where else lint complains. I get the message
> 
> 		c set but no used in function foo
> 

Whats the problem?  Lint is telling you that your loop keeps assigning
a value to c and never ever using it. (Is c in WOM :-)
You could get away with something like this:

	foo()
	{
		if (getchar() != '\n') {
		/* more code here */
		}
	}

guy@sun.uucp (Guy Harris) (07/02/85)

> Unfortunately, this option (-S - ed) is not likely to show you the
> optimized code you would get from running the compiler with
> the -O flag.

No, but

	cc -S -O amor_y_cohetes.c

will run the generated assembly code through the peephole optimizer, so the
resulting ".s" file will show the optimized code.

	Guy Harris

brooks@lll-crg.ARPA (Eugene D. Brooks III) (07/02/85)

> > ...  Any experienced C programmer recognizes this code
> > automatically and produces it without thinking.  You have problems with
> > it because you are not an experienced C programmer yet.
> 
> Rubbish.  "Any experienced programmer should be able to understand that"
> really means "we know it's hard to read, but...".  The idea is to make

No!, it does not mean that.  It means that the novice who has the complaint
about not being able to understand things like

	if((fptr = fopen(filename, "r")) == NULL) {
		printf(stderr, ".....", .....);
		exit(1);
	}



Does not yet clearly understand that in C the expression (a = b) has a value,
which is whats on the RHS of the =, that can be conviently tested!

The same goes for the novice who does not understand why lint complains that
c is not used in

foo()
{
	int c;

	if((c = getchar()) != '\n') {
		SOME CODE
	}
}

fletcher@im4u.UUCP (07/03/85)

In article <2367@sun.uucp> jfarrell@sun.UUCP (Jerry Farrell) writes:
>>
>>One is to write a simple test program and use the '-S'
>>flag of the compiler.
>
>Unfortunately, this option is not likely to show you the
>optimized code you would get from running the compiler with
>the -O flag.  To really see what's being generated, compile
>it, and then look at the object file with something like
>foo,24?ai
>in adb.

Adb to see if your code is optimized?  Now that's
real masochism.  Just do 'cc -O -S foo.c'.  This fails
if you do 'cc -OS foo.c', which is probably what you
were refering to.  This is with 4.2's compiler.  
-- 

Fletcher Mattox, fletcher@ut-sally.ARPA, {ihnp4,seismo,ctvax}!ut-sally!fletcher

chris@umcp-cs.UUCP (Chris Torek) (07/03/85)

Let's not start this again... the value of an assignment is the LHS,
not the RHS.  Ref. ANSI draft X3J11, sec. C.3.16, Assignment Operators:

Constraints:
    Each assignment operator must have an lvalue as its left operand.

Semantics
    An assignment operator stores a value in the object specified by
the lvalue.  An assignment expression has the type of the left operand
and the value of the left operand after the assignment.  The storage
must take place before the value of the assignment is used.

    The order of evaluation of the right operand and the lvalue is
unspecified.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland

arnold@gatech.CSNET (Arnold Robbins) (07/03/85)

> >One is to write a simple test program and use the '-S'
> >flag of the compiler.  This will produce assembly code
> >that you can examine and see what intructions are being
> >generated for any particular expression.
> 
> Unfortunately, this option is not likely to show you the
> optimized code you would get from running the compiler with
> the -O flag.  To really see what's being generated, compile
> it, and then look at the object file with something like
> foo,24?ai
> in adb.

Sorry, but 'cc' is smart enough to run the optimizer on the assembler
if you give it 'cc -S -O foo.c'.  foo.s will be optimized assembly.
-- 
Arnold Robbins
CSNET:	arnold@gatech	ARPA:	arnold%gatech.csnet@csnet-relay.arpa
UUCP:	{ akgua, allegra, hplabs, ihnp4, seismo, ut-sally }!gatech!arnold

Hello. You have reached the Coalition to Eliminate Answering Machines.
Unfortunately, no one can come to the phone right now....

roy@phri.UUCP (Roy Smith) (07/04/85)

> > > ...  Any experienced C programmer recognizes this code
>
> 	if((fptr = fopen(filename, "r")) == NULL)

	Somebody mentioned economy of expression being a good thing;
agreed.  In this particular case the idiom is so well ingrained that I
don't think twice about it.  In fact, doing it any other way would
require more thought.

	Saving a line or two of source makes it that much more likely
that the entire 'phrase' will fit on your screen at one time, enhancing
comprehension.  About the only time I would split the assignment and the
test is when the line would run off the edge of the screen otherwise.
-- 
allegra!phri!roy (Roy Smith)
System Administrator, Public Health Research Institute

henry@utzoo.UUCP (Henry Spencer) (07/04/85)

> > Rubbish.  "Any experienced programmer should be able to understand that"
> > really means "we know it's hard to read, but...".  The idea is to make
> 
> No!, it does not mean that.  It means that the novice who has the complaint
> about not being able to understand things like [assignment inside if]
> does not yet clearly understand that in C the expression (a = b) has a value,
> which is whats on the RHS of the =, that can be conviently tested!

It is entirely possible to understand the semantics of the code fully and
still consider it unnecessarily obscure and hard to read.  The mark of a
good programmer is that his code is *easy* to read, not just *possible* to
read.  Using every obfuscatory feature of the language, perhaps in the
(oft-mistaken) belief that it improves efficiency, and then pleading that
"any experienced programmer should be able to understand that" is the mark
of someone who doesn't understand what this business is about.

"To be clear is professional; not to be clear is unprofessional."
				-- Sir Ernest Gowers
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

jss@sftri.UUCP (J.S.Schwarz) (07/06/85)

>
> Sorry, but 'cc' is smart enough to run the optimizer on the assembler
> if you give it 'cc -S -O foo.c'.  foo.s will be optimized assembly.
> -- 

AT&T compilers these days all come with a tool, call "dis", for
disassembler. that look at object files and tell you exactly what
instructions are in them.

This is neccessary because it is sometimes not possible to look at a
.s and tell exactly what instructions the assembler will produce. For
example an assembler might replace some long forms of jumps by short
forms.

Jerry Schwarz
attunix!jss
AT&T-IS
Summit, N.J.

jfarrell@sun.uucp (Jerry Farrell) (07/07/85)

In article <420@enmasse.UUCP> mhs@enmasse.UUCP (Mike Schloss) writes:
>> I am currently modifying C code, written by someone else,
>> that is incredibly terse. It's paramount that the code
>> be fast, so I presume the code is terse for speed. I'm
>> now curious about a few things:
>
>Sorry but it all depends on your particular compiler
>implementation and the machine you are running on.
>There are two ways to find the answers to your questions.
>One is to write a simple test program and use the '-S'
>flag of the compiler.  This will produce assembly code
>that you can examine and see what intructions are being
>generated for any particular expression.

Unfortunately, this option is not likely to show you the
optimized code you would get from running the compiler with
the -O flag.  To really see what's being generated, compile
it, and then look at the object file with something like
foo,24?ai
in adb.

guy@sun.uucp (Guy Harris) (07/08/85)

> AT&T compilers these days all come with a tool, call "dis", for
> disassembler. that look at object files and tell you exactly what
> instructions are in them.

Well, some AT&T compilers, anyway - the S5R2 documentation describes DIS(1)
as "3B20 only".

> This is neccessary because it is sometimes not possible to look at a
> .s and tell exactly what instructions the assembler will produce. For
> example an assembler might replace some long forms of jumps by short
> forms.

The PDP-11, VAX, and 68000 assemblers I've seen don't replace long jumps
with short jumps; they replace a "generic" jump with a short or long jump.
Then again, for the purposes of inspecting generated code to see "how good
it is", this shouldn't make much of a difference; looking at the ".s" files
should suffice.  The disassembler may be useful for 3Bs; I believe they have
a "generic" assembler language which translates into 3B20 or WE32000-series
binary code.

	Guy Harris

DHowell.ES@Xerox.ARPA (07/09/85)

>	Somebody mentioned economy of expression being a good thing;
>agreed.  In this particular case the idiom is so well ingrained that I
>don't think twice about it.  In fact, doing it any other way would
>require more thought.

Don't think too much, it could be dangerous :-)

But really, if you must keep up the high priesthood of programming, then
go ahead
and use your idioms.  I personally think that programming is a tool for
all and not a science for a few.  Idioms which are believed to be more
efficient (sometimes mistakenly) should be given up in favor of
constructs which are common to most programming languages.  I know that
things can't be done the same in all programming languages, but what can
be, should.  It is simply a matter of making it understandable to all
who are involved with a project, programmers and non-programmers alike.

Dan

jon@cit-vax.ARPA (Jonathan P. Leech) (07/10/85)

> From: DHowell.ES@XEROX.ARPA
> ...
>				    Idioms which are believed to be more
> efficient (sometimes mistakenly) should be given up in favor of
> constructs which are common to most programming languages.  I know that
> things can't be done the same in all programming languages, but what can
> be, should.  It is simply a matter of making it understandable to all
> who are involved with a project, programmers and non-programmers alike.
>
> Dan

    Would you then recommend that we eliminate pointers and structures
from our code? BASIC, FORTRAN and APL don't have them.	I  will  place
myself	out  on  a  limb  by   stating	 that,	 in   my   experience,
non-programmers don't look at code and care that  is  WORKS,  not  how
elegant it is. I would hate to program	in  a  common  subset  of  all
languages. I far prefer to let the comments describe the algorithm and
the implementation be hand-optimized and obscure, if that makes it run
significantly faster.  And sometimes it does. I've been doing a lot of
ray tracing recently, and at >8 hours frame, I CARE about efficiency!

    Jon Leech
    jon@cit-vax-arpa
    __@/

bright@dataio.UUCP (Walter Bright) (07/10/85)

In article <147@mips.UUCP> mash@mips.UUCP (John Mashey) writes:
>It is also useful for human efficiency, once you become accustomed to the
>idiom.  Code must be read and understood by humans; less (signifcant, not
>{}, (), etc) tokens are generally faster, within reasonable limits.
>A similar example is OP= operators; i.e., x = x + 3 requires slightly
>longer to read than x += 3, if only because you don't have tyo check that
>the variables on the right and left are the same.  Trivial in this case,
>but less so when it's  long_identifier1 += 3 instead of
>long_identifier1 += long_identifier1 + 3;

Also, when I program I think "ok, now add 3 to x". I do not think
"ok, now take x, add 3 to it and stuff it back into x". I like the
op= operators because they allow me to program the way I think.

bc@cyb-eng.UUCP (Bill Crews) (07/10/85)

>>> Rubbish.  "Any experienced programmer should be able to understand that"
>>> really means "we know it's hard to read, but...".  The idea is to make
>> 
>>  No!, it does not mean that...

> It is entirely possible to understand the semantics of the code fully and
> still consider it unnecessarily obscure and hard to read.  The mark of a
> good programmer is that his code is *easy* to read, not just *possible* to
> read.  Using every obfuscatory feature of the language, perhaps in the
> (oft-mistaken) belief that it improves efficiency, and then pleading that
> "any experienced programmer should be able to understand that" is the mark
> of someone who doesn't understand what this business is about.

Henry, I have read a number of your postings about the "professionalism" of
code readability, and while I generally applaud and agree with you, there is
nevertheless a feeling I get whenever I read such an article that you
apparently believe that that which is most easily readable by one programmer
is also most easily read by another programmer.  I heartily disagree with
this notion (if it IS your notion).

My most heavily-used language before learning C was PL/I, which looks
much like C *structurally*, BUT without the side effects such as imbedded
assignments that C has.  Perhaps that is the reason I tend to agree with
your statements somewhat.  However, as I get more used to reading C of
various flavors, such constructs HAVE gotten easier for me to read, and they
may someday become easier for me than PL/I-style, if for no other reason than
familiarity.

I tend to target a programmer with a thorough knowledge of the language, but
I try to refrain from forcing that programmer to exercise his powers of
lexical analysis without warrant.  I do NOT assume that that programmer has
read a lot of AT&T code (a dubious distinction) or a lot of anybody else's
code, as you seemed to in a posting not long ago on the topic of indentation
style.  I gathered then that your feeling was that anyone who deviates from
K&R (and, I suppose, AT&T kernel default) style was being UNPROFESSIONAL
by doing so REGARDLESS of how readable one judged this style to be to his
targeted reading population.  Obviously, I disagree with this, perhaps
because I have programmed in C for years and have never done Unix kernel
work.  Without stating where I put my braces (I don't want to start any
more religious wars), I will state that they differ from K&R style, and that
they are positioned such that, in MY estimation, MOST human beings (not just
kernel hackers) that read it can adapt to it based upon NO assumption of their
C reading experience.  And, yes, I suppose I recommend this to others.

-- 

  /  \    Bill Crews
 ( bc )   Cyb Systems, Inc
  \__/    Austin, Texas

[ gatech | ihnp4 | nbires | seismo | ucb-vax ] ! ut-sally ! cyb-eng ! bc

roy@phri.UUCP (Roy Smith) (07/11/85)

I said:
> > [...] the idiom is so well ingrained that I don't think twice about it.

DHowell.ES@Xerox.ARPA (Dan) responded:
> Don't think too much, it could be dangerous :-)

I try not to, it's too much work. :-)

> Idioms which are believed to be more efficient (sometimes mistakenly)
> should be given up in favor of constructs which are common to most
> programming languages. [...] making it understandable to all who are
> involved with a project

	I can't argue with that.  I use "if ((fd = fopen(...)) == NULL)"
not because it runs faster but because I think it makes the program
easier to understand.  We clearly have the same goal; making like easier
on people who have to read our code later on, even if it costs a bit in
execution.  We just disagree on how to reach that goal.

	I also am one of those people who sneer at complex code.  It
just so happens, however, that the 2 particular idioms I have seen
attacked recently (testing and assigning the value of a function at the
same time, and using "i++" instead of "i = i + 1") are among the few that
are on my "so ingrained that I don't think twice" list.  Obviously you
have a different definition for "complex idiom" than I do.  Fair enough.

	I do disagree with your point about using only those features of
C which are in common with other programming languages.  I'm not about to
give up structures and pointers just because FORTRAN doesn't have them.
Nor am I going to do without the conditional, boolean, or various
assignment operators.  They're part of C so why shouldn't I use (not
abuse) them?  Stuff like "i += xtab[foo++->bar[flag?baz1:baz2]]--" is
wantonly confusing; "i += foo->bar" is not.

	More important than what idioms you use is how (or if!) you
comment the code.  How many times have you tried to read 10 pages of
dense code without any useful comments?  Isn't commenting something they
teach in "Intro to Computers and Programming 101"?  So why don't people
do it?  I can deal with figuring out the gritty details of what a certain
idiom means as long as the author gives me a clue as to what is going on.

	It would be nice if the code was *both* simple and commented.
Force to choice one or the other, I'll take the comments any day.  With a
roadmap, I can usually find my way through the convoluted code -- it's
not so easy the other way around.
-- 
allegra!phri!roy (Roy Smith)
System Administrator, Public Health Research Institute

guy@sun.uucp (Guy Harris) (07/12/85)

> I personally think that programming is a tool for all and not a science
> for a few.  It is simply a matter of making it understandable to all
> who are involved with a project, programmers and non-programmers alike.

How inclusive is your "all"?  It's silly to expect everybody to understand
all that's involved in programming.  Should all automobiles be constructed
using technology understandable by "all"?  No.  Most people don't have the
background to understand how a catalytic converter works, or example.  It's
sufficient to construct automobiles so they're *usable* by all.  The same is
true of software.  Software should be usable by the widest possible
collection of people, but the person constructing the program shouldn't care
whether the person using it could understand the code when presented to
them.

The C programming language is a tool.  A person using a tool is assumed to
have some minimum amount of knowledge about the tool they're using.  I think
the "if ((stream = fopen(filename, mode)) == NULL)" idiom, or the "a++"
idiom, is in that minimum.  Sneaky code like "a = (b = c) + d" is not.

	Guy Harris

gwyn@BRL.ARPA (VLD/VMB) (07/14/85)

I have to disagree with your view that "programming is a tool for all
and not a science for a few".  Most of the problems I have encountered
with software have been the direct result of it being produced by
amateurs who were apparently both unaware of the science and
unfamiliar with the proper usage of the tools.

C is meant for experienced, professional programmers; and even those
are expected to learn about the language before dealing with it.  It
makes no sense to argue that all code should be readable by those
unfamiliar with the language; would you prohibit the use of classes
in C++, data structures and pointers in C, etc. simply because people
whose experience is limited to a BASIC primer don't understand them?

dmh@dicomed.UUCP (Dave Hollander) (07/15/85)

This is turning out to be quite a strange discussion.  First, my dictionary
defines "idiom" as an accepted phrase or expression... the i++ construct
is not only accepted by most C programmers but also by the compiler.
Second, why would anyone want to chew up white space in an expression and 
give the mind more tokens to think about?  The rest of the definition involes
"having a meaning *different* than the literal". I can not think of a more
literal definition than K&R did.

The whole poin

jerry@oliveb.UUCP (Jerry Aguirre) (07/17/85)

> But really, if you must keep up the high priesthood of programming, then
> go ahead
> and use your idioms.  I personally think that programming is a tool for
> all and not a science for a few.  Idioms which are believed to be more

Right :-)
And electrictions should no longer use all those technical words like amps
and guage.  They should just talk about big wires and little wires :-)

Electronic schematics should get rid of all those hard to understand
symbols and draw pictures of what each component really looks like :-)

Doctors should use simple terminology like "tummy ache" when writting on
the patients chart :-)

An physisists should just competely stop talking about all those
teeny-tiny things that can't be seen and therefore don't exist :-)

All those priests should stop talking in their secret languages and talk
plain english so that the general public can understand them :-)

				Jerry Aguirre @ Olivetti ATC
{hplabs|fortune|idi|ihnp4|tolerant|allegra|tymix}!oliveb!jerry

oz@yetti.UUCP (Ozan Yigit) (07/17/85)

In article <11554@brl-tgr.ARPA> gwyn@BRL.ARPA (VLD/VMB) writes:
>I have to disagree with your view that "programming is a tool for all
>and not a science for a few".  Most of the problems I have encountered
>with software have been the direct result of it being produced by
>amateurs who were apparently both unaware of the science and
>unfamiliar with the proper usage of the tools.
>
	Umph!!! I have been involved in decus for a long time, and
	have gone through *all* tapes since 1978. These tapes
	contain stuff from Universities (where the Computer Science
	is tought) to many commercial organizations. I could safely
	say that there is *no* one-to-one correspondance between 
	so-called professionals and the awareness of the science of
	programming. You could say that I have encountered more
	trash written (in macro, fortran, basic, C, pascal) by 
	professionals (?) than otherwise. As someone said eons ago:

	An educated fool is often more foolish than 
	an uneducated one.

>C is meant for experienced, professional programmers..

	Is that right ?? It seems the highschool students (Who perhaps
	started out with basic) write just as good C code as
	"professionals", as Lincoln-Sudbury stuff in one of the usenix
	tapes prove. By the way, what does "professional" mean ??
	Someone making a living thru programming ??? I suppose
	"experienced" means someone who has programmed in fortran, basic,
	cobol and apl ??? (Perhaps this does not count - experienced
	means someone who has programmed in C and C alone, the god-given
	tool of higher learning, professionality and superhackerdom !!)

>[it] makes no sense to argue that all code should be readable by those
>unfamiliar with the language; would you prohibit the use of classes
>in C++, data structures and pointers in C, etc. simply because people
>whose experience is limited to a BASIC primer don't understand them?
>
	The idea is to make the program as *clear* as possible, or
	to put it in Einstein's words: "As simple as possible, but
	not simpler". As the obfuscated C contest proves, one can
	write C code that looks like Apl, almost unreadable, yet
	it works. Than you spend about three times as much time
	as it took to write it, to untangle it, perhaps without
	success. What "seems" efficient may not be so, and thus,
	unreadability is a high price to pay for it:

	"Premature optimization is root of all evil" [Kernighan
	and Plauger, The elements of Programming Style, 1978]

	[fill in other classic quotations from Knuth, Jon Bentley
	etc. here]

-- 
Oz	[all wizardesque side effects are totaly unintentional,
	unless stated otherwise..]

	Usenet: [decvax | allegra | linus | ihnp4] !utzoo!yetti!oz
	Bitnet: oz@ [yuleo | yuyetti]
-------------
Support GNU. Consider the 3-muskateers' motto:
	ONE FOR ALL - ALL FOR ONE

henry@utzoo.UUCP (Henry Spencer) (07/17/85)

> 	... I could safely
> 	say that there is *no* one-to-one correspondance between 
> 	so-called professionals and the awareness of the science of
> 	programming. You could say that I have encountered more
> 	trash written (in macro, fortran, basic, C, pascal) by 
> 	professionals (?) than otherwise...
> 
> 	... It seems the highschool students (Who perhaps
> 	started out with basic) write just as good C code as
> 	"professionals", as Lincoln-Sudbury stuff in one of the usenix
> 	tapes prove. By the way, what does "professional" mean ??
> 	Someone making a living thru programming ??? ...

Professionalism is defined by behavior, not credentials.  As your
examples amply demonstrate.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

larry@cca.UUCP (Laurence Schmitt) (07/19/85)

>> 3) Is there really much to be gained by using assignment within
>>    a boolean expression, for example, is
>>
>>	if ((fp = fopen("foo", "r") == NULL) {
>>
>>    really that much faster than
>>
>>	fp = fopen("foo", "r");
>>	if (fp == NULL) {
>
>Again, depends: if "fp" is not a register, the assignment+test is faster,
>since you end up branching after the assignment from r0 to "fp".  If it
>is a register, it comes out the same.  (At least after optimization, usually).
>The first form is never slower, anyway.

In Lattice C on the IBM-PC the two constructs compile exactly the same--no
register declarations involved.

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (07/25/85)

Professionalism is an attitude.  It is not restricted by age or
means of income.  This whole discussion started when someone
complained that standard C idioms should not be used because
they made it harder for unqualified people to read C code.
One of the hallmarks of a professional is skilled use of his
tools..  Would someone explain why it is important for code to
be understood by untrained people?  (This is truly impossible,
in any case, except for rather trivial examples.  An untrained
person is unlikely to understand linked data structures,
dynamic memory allocation, recursion, etc.)

Certainly, many people who are getting paid to program in C
are doing a terrible job of it.  Certainly, it is possible to
produce obscure code in C.  Professional programmers do their
best to produce good code (by all relevant standards, including
maintainability) under existing constraints (time being a major
factor).