Stylistic note on loops

I

Ian Collins

Why? That's ridiculous.

The point of having no {} is that you realise that all the *serious*
stuff is going on inside the while loop statement itself.

It's a great way to confuse readers!
 
S

Stefan Ram

Ian Collins said:
It's a great way to confuse readers!

Indeed, most people will be confused by this, since most
people do not know the C programming language at all.
However, a C programmer will not be confused by this (by
definition).

Have you ever tried to speak for someone from whom you know
that he can not understand English very well? You will have
noticed that you language becomes crippled and unnatural.

We must write code that is as readable as possible. But
we may assume that the reader

- knows C and

- reads every single character of the source code,

otherwise writing readable code is impossible (because we
cannot know upfront which specific part of C a specific
reader will not know or which specific part of our source
code he will miss to read).

One exercise of my programming class for C beginners is
to predict the output of this program:

#include <stdio.h>

int main()
{ printf( "1\n" ); /* writes "1" *
printf( "2\n" ); * writes "2" */ }

.
 
I

Ian Collins

Indeed, most people will be confused by this, since most
people do not know the C programming language at all.
However, a C programmer will not be confused by this (by
definition).

Restoring the context:

James Dow Allen said:
>
> I prefer
> while (*p++ = *q++) {
> }
>

The confusion stems not from the syntax, but from the empty braces, did
he intend there to be some code in there?
 
I

Ian Collins

Ian Collins ha scritto:

and what if sometime in the future you need to meat up a bit the body of
the loop?

You add some. I don't see the relevance of the question.
 
K

Keith Thompson

Ian Collins said:
Restoring the context:



The confusion stems not from the syntax, but from the empty braces, did
he intend there to be some code in there?

One possible alternative is:

while (*p++ = *q++) {
/* nothing */
}

Another is:

while (*p++ = *q++) {
continue;
}
 
M

Malcolm McLean

  One exercise of my programming class for C beginners is
  to predict the output of this program:

#include <stdio.h>

int main()
{ printf( "1\n" ); /* writes "1" *
  printf( "2\n" );  * writes "2" */ }
If I didn't know C at all I'd say that '/' is a line continuation
character of some sort and * comment * is the comment syntax, and the
program consists of two printing statements.
 
M

Malcolm McLean

  We must write code that is as readable as possible. But
  we may assume that the reader

      - knows C and

      - reads every single character of the source code,

  otherwise writing readable code is impossible (because we
  cannot know upfront which specific part of C a specific
  reader will not know or which specific part of our source
  code he will miss to read).
Yesterday I translated a Python routine into C. I've don't know Python
- I've glanced at some source but I've never read a Python primer nor
used a Python compiler/interpreter (I don't even know which). However
I was able to complete the task successfully. It's a combination of
knowing what the function was intended to achieve and the fact that
most programming languages encode similar operations with similar
syntax.
 
M

Malcolm McLean

Is that a long winded way of saying you wrote some C?

If you are claiming that converting Python manually into C is
straightforward then you're right : you haven't got a clue about Python.
It was an alignment algorithm. Whilst I know basically how it works,
it's tricky to get all the details right and my attempt to write in C
from scratch was taking too long. So I pulled out an existing routine
in Python and just manually translated the logic to C. The only
difficult bit was that the Python used an associative array, which of
course you can't translate directly to C. However it wasn't necessary
and it was possible to get rid of it by hard-coding.
 
J

James Dow Allen

It's a great way to confuse readers!

I find these objections baffling. It's only a short slide from
while (foo) ;
to
while (foo) gak;
so the construction
while (foo) {
}
is the clearest way *to emphasize* that the while-body is empty!

An ironic fact is that, if I'm sure the while-body will remain
empty "forever" I might use a third form
while (foo)
;
but posted the form with braces as being "better style"! :)

But finally, and more importantly, there is something else about
these responses that astounds me. My earlier post was on a
completely different matter -- languages that consider unused
variables to be "fatal errors" and my then-thought amusing
post on the topic. No one responded to that, focussing instead
on the trivial stylistic variation I mentioned at the end of
my post almost parenthetically.

Fine. *AND YET NONE OF YOU DELETED* the other matter from the
quoted text: it's still visible in this response, traveling
through two quoters! You quibble about the placement of
white space in a C program, yet don't know enough to do trivial
edits of quoted material in Usenet responses!!

Increasingly, this newsgroup cracks me up.

James Dow Allen
 
L

Lew

James said:
But finally, and more importantly, there is something else about
these responses that astounds me. My earlier post was on a
completely different matter -- languages that consider unused
variables to be "fatal errors" and my then-thought amusing
post on the topic. No one responded to that, focussing instead
on the trivial stylistic variation I mentioned at the end of
my post almost parenthetically.

Perhaps no one cared about the other point.
Fine. *AND YET NONE OF YOU DELETED* the other matter from the

OOOOO! Snap!
quoted text: it's still visible in this response, traveling
through two quoters! You quibble about the placement of

Awwwww, gee whiz!
white space in a C program, yet don't know enough to do trivial
edits of quoted material in Usenet responses!!

Is it really a matter of knowledge? Somehow I don't think so.
Increasingly, this newsgroup cracks me up.

Blah, blah, blah. (BTW, which of the two newsgroups did you mean by "this" one?)

And what exactly did your post contribute? Nothing.
 
B

BGB / cr88192

but, there are many other cases where one will end up using loops like
this.

<--
for(i=0;i<N;i++)
/* do work here */

or

for(i=0;array != sentinel;i++)
/* do work here */

is my preferred method, because it doesn't corrupt the pointers. In
the olden days indexing used to be a little bit slower because the
compiler would create an extra variable and offset calculation.
However that's no longer much of a concern.
-->

it is often still a little slower, as the compiler will often calculate the
offset in a secondary register and then use an indirect memory load to
access it.

j=*p++;
is still often a little faster than:
j=p;

although, for most cases the differences are small enough to be ignored.

all this may sometimes lead to loops like:
for(p=start; p<end; p++)
... do something with p ...

nevermind this:
for(obj=first; obj; obj=obj->next)
... do something with obj ...


but, in general, one is better advised to leave things to style, and only
really try to micro-optimize in cases where the profiler says it is
needed...
 
M

Malcolm McLean

it is often still a little slower, as the compiler will often calculate the
offset in a secondary register and then use an indirect memory load to
access it.

j=*p++;
is still often a little faster than:
j=p;

although, for most cases the differences are small enough to be ignored.


I've only got tcc, which though a fine compiler isn't really intended
to be cutting edge state of the art.

Can someone compile these two to assembly with a mainstream compiler
like gcc / MS Visual C ?

char *strcpyindex(char *dest, char *src)
{
int i;

for(i=0;src;i++)
dest = src;
dest = 0;
return dest;
}

char *strcpyptr(char *dest, char *src)
{
char *answer = dest;

while(*dest++ = *src++);
return answer;
}
 
J

Joshua Cranmer

char *strcpyindex(char *dest, char *src)
{
int i;

for(i=0;src;i++)
dest = src;
dest = 0;
return dest;
}


[gcc -O2]
xorl %ebx, %ebx
movl 8(%ebp), %eax
movzbl (%esi), %ecx
testb %cl, %cl
je .L3
..L6:
addl $1, %edx
movb %cl, (%eax,%ebx)
movzbl (%esi,%edx), %ecx
movl %edx, %ebx
testb %cl, %cl
jne .L6
..L3:
movb $0, (%eax,%ebx)
char *strcpyptr(char *dest, char *src)
{
char *answer = dest;

while(*dest++ = *src++);
return answer;
}

..L10:
movzbl (%ebx,%edx), %ecx
movb %cl, (%eax,%edx)
addl $1, %edx
testb %cl, %cl
jne .L10

-O2 converted the arrays into pointers (kind of), but, oddly enough,
didn't think to eliminate the use of %ebx as redundant with %ebx
(perhaps array-to-pointer conversion pass happens after subexpression
elimination?). Otherwise, the two loops are exactly identical.
 
T

Tom Anderson

Yesterday I translated a Python routine into C. I've don't know Python -
I've glanced at some source but I've never read a Python primer nor used
a Python compiler/interpreter (I don't even know which). However I was
able to complete the task successfully. It's a combination of knowing
what the function was intended to achieve and the fact that most
programming languages encode similar operations with similar syntax.

Python has been called 'executable pseudocode'. If written cleanly, it is
highly readable, even to those who don't know it.

If written badly, of course, it's as bad as the cleanest bits of perl.

tom
 
T

Tom Anderson

One exercise of my programming class for C beginners is
to predict the output of this program:

#include <stdio.h>

int main()
{ printf( "1\n" ); /* writes "1" *
printf( "2\n" ); * writes "2" */ }

Crafty!

But will it even compile, given the lack of a return statement in a
non-void-returning method?

Maybe it will, being C. It bloody well shouldn't though!

tom
 
B

BartC

Python has been called 'executable pseudocode'. If written cleanly, it is
highly readable, even to those who don't know it.

I think Python is the last language I'd use for pseudocode. No-one writing
Python can resist using all it's features which renders it incomprehensible
to anyone else. And for porting code, it is also necessary to duplicate it's
myriad libraries.

Probably Lua is better for that role, being far simpler with less built-in
stuff.
 
E

Eric Sosman

Crafty!

But will it even compile, given the lack of a return statement in a
non-void-returning method?

Maybe it will, being C. It bloody well shouldn't though!

Under C90 rules it will compile, but the effect is undefined
(unless the environment chooses to ignore the returned value).
Under C99 rules it will compile, and will return zero.

I agree heartily with your final sentence.
 
S

Stefan Ram

Eric Sosman said:
I agree heartily with your final sentence.

By this you agree with a sentence with an expletive, but
whatever: This reminds my of one of my own style rules, that
I can apply to both topics discussed here: loops and the
main function:

»When two wordings are equivalent, use the shorter one.«

Thus, »; while( example() );«, not »; while( example() ){}«,
and »int main(){}«, not »int main(){ return 0; }«.

(A semicolon was added above in front of the »while«
to clarify that this is not the tail of a do loop.)

This rule, however does not apply to formatting (white space),
so »{ return 0; }« is ok, even if »{return 0;}« would be
shorter.

In the case of »while( 1 )« versus »for( ;; )« I am not sure:
The for loop is shorter in terms of non-whitespace characters
while the while loop is shorter in terms of tokens.
 
S

Stefan Ram

Patricia Shanahan said:
Do you consider this rule a way of making the code as readable as
possible, or a substitute for that approach?

Possibly, we sometimes make terms absolute, which really
need a referent. »Readable« might be a predicate of a text
and a reader:

Readable( text, reader ),

not of a text alone

Readable( text ).

Having said this, I see this rule as a rule that can coexist
with a rule requiring readability and maintainability but in
parts has a different scope.

It is much more precise. While one man's readability could
be another man's obfuscation, the lenght of a code segment
is more objective.

Usually, any unnecessary part will catch the attention of
the reader and might disctract him or make him think about
something irrelevant (that is, »why was this verbose/
unnecessary part added here?«).

For example, we have:

cos 2x = cos² x - sin² x

If this is written as

cos 2x =( cos² x )-( sin² x ),

, one man might say »Great! Now I finally see the
precedences - that 's more readable!«, another man might say
»Well, what does the author want to convey with the
additional redundant braces?«. So, it might be difficult to
be sure what is »more readable« of the two. In such case my
brevity rule helps to find a »canonical« form, that is, to
prefer the first one.

But I see my rule more in terms of token counts than in
terms of letter counts, so I do not want to oppose variable
names to be sufficiently long to carry enough meaning to
help the reader to understand the code.

I would say that, when it is obvious what is more readable,
the more readable variant should be chosen and would restrict
my brevity rule to a subordinate rôle, that is, only when
the readability of two choice does not differ that much or
can not be determined precisely enough to make a clear choice,
the I would go for the shorter one.

It should have become clear that I do not see any problem
whatsoever to read a loop body made of a semicolon statement
solely or a main function implicitly returning a value, so
in these cases, I do not hesitate to apply my brevity rul
rule. I would not apply it, should it's result look
obviously less readable to me, because in this case,
readability would be more important than brevity.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top