Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Alternatives to modifying loop var in the loop.

185 views
Skip to first unread message

Matt

unread,
Dec 27, 2013, 2:14:10 AM12/27/13
to
I'm sure I've read somewhere that it's considered bad practice to modify
the value of the variable on the right of a comparison operator inside
the loop concerned. If I have remembered this correctly then what is the
usual way to do this:

int del_at(int i, int len, type arr[])
{
int j;
for(j = i + 1; j < len; j++, i++)
arr[i] = arr[j];

return len - 1;
}

and somewhere else:

type arr[len];
/*fill it with some items*/

int i;
for(i=0; i < len; i++){
if(needs_deleting(arr[i]))
len = del_at(i, len, arr);
}

This code works as intended and isn't complained about by gcc -Wall.

Isn't one of the things about C that you're able to do what you want?

Why shouldn't I do it the way I showed above? Could it come back to bite
me somehow?

Matt.

glen herrmannsfeldt

unread,
Dec 27, 2013, 2:24:31 AM12/27/13
to
Matt <ma...@clickertraining.co.nz> wrote:

> I'm sure I've read somewhere that it's considered bad practice to modify
> the value of the variable on the right of a comparison operator inside
> the loop concerned.

There are many things that it is better not to do because
readers won't expect it. Others to help avoid common mistakes.

> If I have remembered this correctly then what is the
> usual way to do this:

> int del_at(int i, int len, type arr[])
> {
> int j;
> for(j = i + 1; j < len; j++, i++)
> arr[i] = arr[j];
> return len - 1;
> }

Well, this one doesn't modify len while the loop is active...

> and somewhere else:

> type arr[len];
> /*fill it with some items*/

> int i;
> for(i=0; i < len; i++){
> if(needs_deleting(arr[i]))
> len = del_at(i, len, arr);
> }

I don't see a problem with it, but it should be well commented to
be sure anyone reading it understands what it does.

> This code works as intended and isn't complained about by gcc -Wall.

> Isn't one of the things about C that you're able to do what you want?

Yes, especially for entries to the IOCCC. But other than that,
you want to write so it is more readable.

> Why shouldn't I do it the way I showed above? Could it come
> back to bite me somehow?

It is common, for example, to write the inner loop of quicksort
with both i and j varying, and both in the comparison. In that case,
though, it is pretty obvious what it is doing.

-- glen

Willem

unread,
Dec 27, 2013, 5:45:46 AM12/27/13
to
Matt wrote:
) I'm sure I've read somewhere that it's considered bad practice to modify
) the value of the variable on the right of a comparison operator inside
) the loop concerned. If I have remembered this correctly then what is the
) usual way to do this:
)
) int del_at(int i, int len, type arr[])
) {
) int j;
) for(j = i + 1; j < len; j++, i++)
) arr[i] = arr[j];
)
) return len - 1;
) }
)
) and somewhere else:
)
) type arr[len];
) /*fill it with some items*/
)
) int i;
) for(i=0; i < len; i++){
) if(needs_deleting(arr[i]))
) len = del_at(i, len, arr);
) }

The usual way to do that, specifically, is to do it in a single loop, to
avoid having to copy and re-copy the items:

int j = 0;
for (i = j = 0; i < len; i++)
if (!needs_deleting(arr[i]))
arr[j++] = arr[i];
len = j;

) This code works as intended and isn't complained about by gcc -Wall.
)
) Isn't one of the things about C that you're able to do what you want?
)
) Why shouldn't I do it the way I showed above? Could it come back to bite
) me somehow?

Perhaps the 'bad practice' you read about was this idiom, which is used to
avoid 'break' statements:

for (i = 0; i < len; i++) {
if (needs_ending(arr[i])) {
i = len;
} else {
do_something_with(arr[i]);
}
}


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT

Tim Prince

unread,
Dec 27, 2013, 7:11:54 AM12/27/13
to
On 12/27/2013 5:45 AM, Willem wrote:
> Matt wrote:
> ) I'm sure I've read somewhere that it's considered bad practice to modify
> ) the value of the variable on the right of a comparison operator inside
> ) the loop concerned.
> Perhaps the 'bad practice' you read about was this idiom, which is used to
> avoid 'break' statements:
>
> for (i = 0; i < len; i++) {
> if (needs_ending(arr[i])) {
> i = len;
> } else {
> do_something_with(arr[i]);
> }
> }
>
This one may prevent or break optimizations based on setting the loop
count prior to entering the loop. The break also would prevent such
optimizations, but the compiler would have no excuse for missing it.


--
Tim Prince

Eric Sosman

unread,
Dec 27, 2013, 9:00:16 AM12/27/13
to
On 12/27/2013 2:14 AM, Matt wrote:
> I'm sure I've read somewhere that it's considered bad practice to modify
> the value of the variable on the right of a comparison operator inside
> the loop concerned. If I have remembered this correctly then what is the
> usual way to do this:
>
> int del_at(int i, int len, type arr[])
> {
> int j;
> for(j = i + 1; j < len; j++, i++)
> arr[i] = arr[j];
>
> return len - 1;
> }
>
> and somewhere else:
>
> type arr[len];
> /*fill it with some items*/
>
> int i;
> for(i=0; i < len; i++){
> if(needs_deleting(arr[i]))
> len = del_at(i, len, arr);
> }
>
> This code works as intended and isn't complained about by gcc -Wall.

Since you've not revealed what is "intended," we can't dispute
your claim that it "works." Still, it looks fragile to me. Consider
this possible concretization:

typedef int type;

int needs_deleting(type value) {
return value % 2 == 0; // even numbers are unlucky
}

type arr[] = { 1, 2, 4, 6, 7 };
int len = 5;

Given this, it sort of looks like your code should squeeze out all
the even numbers and leave only the two odds. However, what your
code actually does is set arr[] to {1, 4, 7, 7, 7} and len to 3:
The 4 has survived deletion. More generally, *any* value immediately
following a deleted element will survive, whatever needs_deleting()
might say.

> Isn't one of the things about C that you're able to do what you want?

There are lots of things I want to do for which C is no help.
Your wants are probably different from mine.

> Why shouldn't I do it the way I showed above? Could it come back to bite
> me somehow?

It all depends on "intended." The code does X, and if X is
what you intended, then no: The code will not come back to bite you.
But if you actually intended X', you've already felt its fangs.

--
Eric Sosman
eso...@comcast-dot-net.invalid

James Kuyper

unread,
Dec 27, 2013, 10:41:06 AM12/27/13
to
On 12/27/2013 02:14 AM, Matt wrote:
> I'm sure I've read somewhere that it's considered bad practice to modify
> the value of the variable on the right of a comparison operator inside
> the loop concerned.

The validity of that guideline depends upon what you're doing. For
instance, if a loop starts with

for(int item=0; item < item_count; item++)

then it is potentially very confusing to change either item or
item_count within the loop. That doesn't mean you shouldn't do it - if
there's sufficiently good reason so do so, then you should; but you
should draw attention to the lines where you perform the modification by
inserting comments.

On the other hand, I've written code to do a bracketed binary search of
a sorted array like the following:

while(low < high)
{
int mid = (low+high)/2;
if(array[mid] < x)
low = mid+1;
else
high = mid;
}

The fact that this code modifies both "low" and "high" inside the loop
is not a problem, because it's very clear why and how it's modifying them.

Matt

unread,
Dec 27, 2013, 6:36:08 PM12/27/13
to
On 28/12/13 03:00, Eric Sosman wrote:

> you've not revealed what is "intended,"

I'm implementing the Knuth 5 guess algorithm for solving mastermind puzzles:

http://en.wikipedia.org/wiki/Mastermind_%28board_game%29#Five-guess_algorithm

>----<
#define PEGS 4
#define COLORS 6
#define ALL 1296 // (int)pow(COLORS, PEGS)

typedef struct{
int code[PEGS];
int knuth_number; // how many guesses this one gets solved in
} mcode;

mcode all_codes[ALL];
int npos;// the number of remaining possibilities for the secret code
// after processing the feedback from each guess.
>----<

Before the first guesss:

>----<
npos = ALL;
>----<

At each pass through the algorithm possibilities are eliminated
until npos == 1. Here is sample output using all_codes[1294]:

>----<
solve 5554
guess 0011 0,0
npos 256
guess 2234 1,0
npos 18
guess 2545 1,2
npos 3
guess 0044 1,0
npos 1
guess 5554 4,0
solve 5554 K5
>----<

Full context: http://code.mattsmith.org.nz/mastermind/ansic/

In different incarnations of this project I've used different ways of
managing the list of remaining possibilities. The actual codes, indexes,
manual memory allocation and freeing, high level c++ libraries. Now I'm
writing the game in plain ansi c as an ncurses application for
gnu/linux, then porting it piece by piece to an older compiler to build
as a prodos .SYS program for apple][.

On modern hardware it makes no difference how you do things as long as
it works. Except that I want to learn which ways are faster, which are
slower, which more or less elegant, which appropriate or not for a given
situation.

For the prodos version though there is a practical reason to learn this
stuff: speed. As currently implemented the prodos version takes about 15
min to come up with the first guess. This in an emulator at top speed.
Can't really expect a user to sit there on his chuff while the computer
player is "thinking" for this long.

> it looks fragile to me. Consider
> this possible concretization:
>
> typedef int type;
>
> int needs_deleting(type value) {
> return value % 2 == 0; // even numbers are unlucky
> }
>
> type arr[] = { 1, 2, 4, 6, 7 };
> int len = 5;
>
> Given this, it sort of looks like your code should squeeze out all
> the even numbers and leave only the two odds. However, what your
> code actually does is set arr[] to {1, 4, 7, 7, 7} and len to 3:
> The 4 has survived deletion. More generally, *any* value immediately
> following a deleted element will survive, whatever needs_deleting()
> might say.
>

All true. I "tested" del_at using

int arr[] = {0,1,2 ......,99};

and

if(arr[i] % 5 == 0)
del_at(i, ...);

then assumed from that it would probably work in other situations. Not cool.

Pretty sure just your last point above excludes my del_at code from
working in the mastermind program because there are big contiguous
blocks of possibilities which get eliminated.

Thanks for your help.

Matt.

Matt

unread,
Dec 27, 2013, 6:37:47 PM12/27/13
to
On 27/12/13 23:45, Willem wrote:
> The usual way to do that, specifically, is to do it in a single loop, to
> avoid having to copy and re-copy the items:
>
> int j = 0;
> for (i = j = 0; i < len; i++)
> if (!needs_deleting(arr[i]))
> arr[j++] = arr[i];
> len = j;

Thanks this is much better than what I did.

Matt.

Ben Bacarisse

unread,
Dec 28, 2013, 2:19:49 AM12/28/13
to
Matt <ma...@clickertraining.co.nz> writes:

<snip>
> Pretty sure just your last point above excludes my del_at code from
> working in the mastermind program because there are big contiguous
> blocks of possibilities which get eliminated.

Two things to consider: First, depending on the amount of data being
copied after the delete, you might find that memmove might be better
than your own loop. Second, you might want to alter the data structure.
Deletes from a linked list are fast, or you could keep a "deleted" flag
for every element so that nothing in the array need actually be copied.

But I also had a look a the code, and you have a redundant loop in
getscore which is the time-limiting function right now. You can count
the matching colours without looping over colours.

--
Ben.

Eric Sosman

unread,
Dec 28, 2013, 9:04:07 AM12/28/13
to
On 12/27/2013 6:36 PM, Matt wrote:
> On 28/12/13 03:00, Eric Sosman wrote:
>
>> you've not revealed what is "intended,"
>
> I'm implementing the Knuth 5 guess algorithm for solving mastermind
> puzzles:
> [...]
> At each pass through the algorithm possibilities are eliminated
> until npos == 1. [...]

Then you are doing *way* too much work. I'd suggest something
more along the lines of

int newlen = 0;
for (int i = 0; i < len; ++i) {
if (should_keep(array[i]))
array[newlen++] = array[i];
}
len = newlen;

... which moves each survivor once and each decedent zero times,
instead of moving both many times as they slide down again and
again and again to cover vacancies behind them.

> For the prodos version though there is a practical reason to learn this
> stuff: speed. As currently implemented the prodos version takes about 15
> min to come up with the first guess. This in an emulator at top speed.
> Can't really expect a user to sit there on his chuff while the computer
> player is "thinking" for this long.

I'm not familiar with ProDOS, nor with whatever emulator you're
using, but the time seems overlong by maybe two orders of magnitude.
I recall writing a MasterMind game in the early 1970's and it made
its guesses faster than I could make mine. I suspect something's
seriously amiss with your setup -- could be your program, could be
a pitifully poor emulator, could be a lot of things -- but it doesn't
seem right that a machine from four decades ago (IBM S/370 145) could
out-perform current hardware on this kind of task.

--
Eric Sosman
eso...@comcast-dot-net.invalid

Aleksandar Kuktin

unread,
Dec 28, 2013, 9:33:47 AM12/28/13
to
Hi all.

On Fri, 27 Dec 2013 09:00:16 -0500, Eric Sosman wrote:

> On 12/27/2013 2:14 AM, Matt wrote:
>> I'm sure I've read somewhere that it's considered bad practice to
>> modify the value of the variable on the right of a comparison operator
>> inside the loop concerned. If I have remembered this correctly then
>> what is the usual way to do this:
>>
>> int del_at(int i, int len, type arr[])
>> {
>> int j;
>> for(j = i + 1; j < len; j++, i++)
>> arr[i] = arr[j];
>>
>> return len - 1;
>> }
>>
>> and somewhere else:
>>
>> type arr[len];
>> /*fill it with some items*/
>>
>> int i;
>> for(i=0; i < len; i++){
>> if(needs_deleting(arr[i]))
>> len = del_at(i, len, arr);
>> }
>>
>> This code works as intended and isn't complained about by gcc -Wall.

[snip]

> More generally, *any* value immediately
> following a deleted element will survive, whatever needs_deleting()
> might say.

One possible way to solve the survivability error is to backtrack the
counter.

for (i=0; i<len; i++)
if (needs_deleting(arr[i])) {
len = del_at(i, len, arr);
i--;
}

The solution proposed by Willem and Eric is obviously better because
there is infinitelly less copying going on, but I am interested in the
general opinion on backtracking counters (unless that is also heavily
dependent on context). Is such a practice considered un-elegant, or
perhaps something similar?

Eric Sosman

unread,
Dec 28, 2013, 11:30:21 AM12/28/13
to
On 12/28/2013 9:33 AM, Aleksandar Kuktin wrote:
>[...]
> One possible way to solve the survivability error is to backtrack the
> counter.
>
> for (i=0; i<len; i++)
> if (needs_deleting(arr[i])) {
> len = del_at(i, len, arr);
> i--;
> }
>
> The solution proposed by Willem and Eric is obviously better because
> there is infinitelly less copying going on, but I am interested in the
> general opinion on backtracking counters (unless that is also heavily
> dependent on context). Is such a practice considered un-elegant, or
> perhaps something similar?

It doesn't seem to me that "elegance" is a useful criterion
for making decisions about software tactics. Like beauty, elegance
is in the eye of the beholder, and beholders will disagree. I've
heard "elegant" used to describe some stupendous botches, like
moving a file from one directory to another by copying it across
a network to an entirely different system and then copying it back
(true story, I kid you not)!

To my way of thinking, the most important consideration should
be correctness: Does the software (or fragment) do what is desired,
under all circumstances that might arise? Incorrectness, not
inefficiency, was the biggest flaw in the original code. After
that should come clarity and/or elegance, because they help build
confidence in the code's correctness and because they make it easier
to alter and extend. Performance is less important than either,
usually, unless it's so bad that it compromises correctness (the
O.P. spoke of a fifteen-minute wait for his game program to make
its first move; that's probably not "within specification").

So, back to the loop question: IMHO, fiddling with what looks
like a loop counter and/or fiddling with the termination condition
are threats to clarity. If you can recast the loop in a simpler
and more readable form, you should consider doing so. The loop
forms that I think most readable (but remember the "eye of the
beholder" stuff) are

// Counted loops:
for (i = START; i < LIMIT; i += STEP) ...
for (i = LIMIT; (i -= STEP) >= START; ) ...

// Predicated loops:
for (i = START; predicate(i); i += STEP) ...
while (predicate()) ...

Here, I'm supposing that START, LIMIT, and STEP are values that
do not change in the loop; they may not be "constants" in the C
sense, but if they vary while the loop is in progress the code
may well be harder to follow. But there are exceptions even to
this fuzzy guideline; for example a binary search:

for (lo = START, hi = LIMIT; lo < hi; ) {
mid = lo + (hi - lo) / 2;
if (key < array[mid])
hi = mid;
else if (key > array[mid])
lo = mid + 1;
else
return mid; // found it!
}
return -1; // not there (sob!)

Even though *both* participants in this loop's predicate are
subject to change during the loop, I don't think people will
find it confusing. If there's any doubt, perhaps it should be
rewritten as:

lo = START;
hi = LIMIT;
while (lo < hi) ...

Finally, to your "backtracking counter" loop: I really,
really don't like it. A better formulation, I think, would be

for (i = 0; i < len; ) {
if (needs_deleting(arr[i])
len = del_at(i, len, arr);
else
++i;
}

... because the reader will not be fooled by the familiar-looking
`i++' in the first line and perhaps overlook the unfamiliar in-loop
adjustment. Seeing no index adjustment at all in the `for', he
will look inside the loop to learn what happens to `i', and (I
think) his route to understanding will be a shorter one.

--
Eric Sosman
eso...@comcast-dot-net.invalid

Matt

unread,
Dec 28, 2013, 6:14:14 PM12/28/13
to
On 28/12/13 20:19, Ben Bacarisse wrote:
> you have a redundant loop in
> getscore which is the time-limiting function right now. You can count
> the matching colours without looping over colours.

Cool I'll look at this thanks.

Matt

unread,
Dec 28, 2013, 6:42:46 PM12/28/13
to
On 29/12/13 03:04, Eric Sosman wrote:
> I recall writing a MasterMind game in the early 1970's and it made
> its guesses faster than I could make mine. I suspect something's
> seriously amiss with your setup -- could be your program, could be
> a pitifully poor emulator, could be a lot of things -- but it doesn't
> seem right that a machine from four decades ago (IBM S/370 145) could
> out-perform current hardware on this kind of task.

I'm pretty sure it'll turn out to be my program. As a self-taught hobby
programmer I just have no background in any of this stuff. Sometimes I
think I'll go back to school but at the universities where I live it's
java, then some java, then more java so I'm not convinced I would learn
what I want to anyway.

One point of pedantry: on current hardware my code also guesses faster
than I can. The Apple //e was current in 1983. Your point is 100% correct.

The emulator is http://linapple.sourceforge.net/. Quoting:

> instead of inventing a wheel, I decided to port AppleWin to Linux,
>using SDL library (Simple DirectMedia Layer) and changing all Windows
>API functions to their POSIX equivalents.

From lurking on comp.apple2.sys.* it seems like AppleWin is considered
to be one of the better ][ emulators going around. I'm going to look at
my code first, trying different emulators is lower down the list.

First I'll fix get_score according to Ben's advice then maybe try a
linked list since that is something I want to learn anyway.

Thanks all,

Matt.







Matt

unread,
Dec 28, 2013, 8:41:43 PM12/28/13
to
On 29/12/13 12:42, Matt wrote:
> On 29/12/13 03:04, Eric Sosman wrote:
>>it doesn't
>> seem right that a machine from four decades ago (IBM S/370 145) could
>> out-perform current hardware on this kind of task.

[...]
>
> One point of pedantry: on current hardware my code also guesses faster
> than I can. The Apple //e was current in 1983. Your point is 100% correct.
>
>

I can word this more clearly:

Imo the S/370 145 is not outperforming current(2013) hardware. It is
outperforming current(1983) hardware. In any case the hardware isn't
realy the issue. Allowing for hardware Eric's code outperforms mine. I
have a lot to learn:-).

Matt

unread,
Dec 29, 2013, 3:58:29 AM12/29/13
to
On 28/12/13 20:19, Ben Bacarisse wrote:
> you have a redundant loop in
> getscore which is the time-limiting function right now. You can count
> the matching colours without looping over colours.

http://code.mattsmith.org.nz/mastermind/bits/new_get_score.c

I still iterated through colors once to set some stuff to 0.
Even then I'm never telling anyone how long it took me. I have a gift
for making simple things complicated lol. It always amazes me how
something you do as a human without even knowing how you do it (scoring
your opponents guess in a board game) can be so difficult (for me
anyway) to explain to a computer.

$ time ./testfunc old

real 0m0.255s
user 0m0.252s
sys 0m0.004s

$ time ./testfunc new

real 0m0.150s
user 0m0.144s
sys 0m0.004s

$ cat /proc/cpuinfo
processor : 0
vendor_id : AuthenticAMD
cpu family : 21
model : 2
model name : AMD FX(tm)-6300 Six-Core Processor
stepping : 0
microcode : 0x6000803
cpu MHz : 1400.000
[...]

$ cat /proc/meminfo
MemTotal: 33048056 kB
[...]

It's beer o'clock in utc +12 land. Tomorrow I plug new_get_score in to
the apple//e code.

Seebs

unread,
Dec 29, 2013, 4:44:25 AM12/29/13
to
On 2013-12-28, Eric Sosman <eso...@comcast-dot-net.invalid> wrote:
> It doesn't seem to me that "elegance" is a useful criterion
> for making decisions about software tactics.

Oh, I'd disagree on that. I think it's one of the best. Unfortunately,
that doesn't necessarily make it flawless.

> Like beauty, elegance
> is in the eye of the beholder, and beholders will disagree. I've
> heard "elegant" used to describe some stupendous botches, like
> moving a file from one directory to another by copying it across
> a network to an entirely different system and then copying it back
> (true story, I kid you not)!

That is certainly a problem, but I would argue that this is best resolved
by pointing out the ways in which it fails to be elegant.

But elegance solves a really useful problem, which is getting some of
our very fast cognitive function that isn't consciously available aligned
to a task that helps us get things fixed.

> To my way of thinking, the most important consideration should
> be correctness: Does the software (or fragment) do what is desired,
> under all circumstances that might arise?

While this is certainly very important, I think another thing, while
strictly speaking less important, is functionally a prerequisite for
making useful decisions: Can we *tell* whether the software does what
we want?

And that's where "elegant" can become an important consideration.

> Incorrectness, not
> inefficiency, was the biggest flaw in the original code. After
> that should come clarity and/or elegance, because they help build
> confidence in the code's correctness and because they make it easier
> to alter and extend.

I would say that if code is sufficiently unclear, that evaluating
its correctness is quite likely to be less useful than changing it so
you can at least tell what it's doing.

If you can't evaluate a criterion, it's not useful to you, and "elegant"
tends to be a very close proxy for "easily understood and checked for
correctness".

-s
--
Copyright 2013, all wrongs reversed. Peter Seebach / usenet...@seebs.net
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
Autism Speaks does not speak for me. http://autisticadvocacy.org/
I am not speaking for my employer, although they do rent some of my opinions.

Ben Bacarisse

unread,
Dec 29, 2013, 6:10:36 AM12/29/13
to
Matt <ma...@clickertraining.co.nz> writes:

> On 28/12/13 20:19, Ben Bacarisse wrote:
>> you have a redundant loop in
>> getscore which is the time-limiting function right now. You can count
>> the matching colours without looping over colours.
>
> http://code.mattsmith.org.nz/mastermind/bits/new_get_score.c
>
> I still iterated through colors once to set some stuff to 0.

You can use '= {0};' as the initialiser to zero the arrays.

<snip>
--
Ben.

Dr Nick

unread,
Dec 29, 2013, 8:46:34 AM12/29/13
to
I've not checked to see if it's still the case, but one of the most
irritating features of GCC that I've come across is that it warns that
this is not a complete initiator.

Now if I've done = {1,2,3,4,5,6} for a 7 element array, I may well not
want the last initialised to 0, so I can understand the warning. But =
{0} should be a special case.

Of course, you can always turn off warnings etc, but this particular one
seemed especially irritating.

Eric Sosman

unread,
Dec 29, 2013, 10:16:12 AM12/29/13
to
I think that "elegance" means different things to the two
of us (eye of the beholder, again). The quality you describe
as "elegance" is something I'd prefer to call "clarity," and I
agree that it's a desirable attribute regardless of whether you
call it clarigance or eleganity.

"Clarity" is something one could attempt to measure, much as
one measures "readability" in natural language. You could show
scraps of code to suitable populations of readers, ask them
verifiable questions about what the code does, run t-tests and
so on to decide whether scrap A is more or less clear than B, ...
This is the sort of experiment one can imagine performing.[*]

But is there an experiment that could attempt to measure
"elegance?" One could show code samples to a bunch of fashion
writers, I guess, but ... Can you think of any way to elevate
opinion and taste to something measurable? I can't.

... and that's why I don't think "elegance" is a useful
criterion: If you can't measure it, you can't tell whether it's
present or absent, or to what degree. And if you can't really
say whether A is more or less elegant than B, you can't make
good decisions based on how elegant they are or aren't.

[*] IIRC, Weinberg reported on a similar experiment in "The
Psychology of Computer Programming." Groups of computer science
students read the same piece of code, either in its original form
or with the comments removed. The students who saw the UNcommented
code found and fixed more of its errors than those who had the
"benefit" of the commentary ...

--
Eric Sosman
eso...@comcast-dot-net.invalid

Phil Carmody

unread,
Dec 29, 2013, 11:23:52 AM12/29/13
to
Seebs <usenet...@seebs.net> writes:
> On 2013-12-28, Eric Sosman <eso...@comcast-dot-net.invalid> wrote:
> > It doesn't seem to me that "elegance" is a useful criterion
> > for making decisions about software tactics.
>
> Oh, I'd disagree on that. I think it's one of the best. Unfortunately,
> that doesn't necessarily make it flawless.

I'm not sure with whom I agree, as I agree with both!

Perhaps "elegance" is a tag that is only applied to code *after*
it's been checked that it seems correct? (2 wiggle words there,
checking isn't proving, and seems covers many sins!) One of the
best things about elegant code is that it is easily checked for
correctness.

Correct code wasn't attempting to evolve in the direction of elegance,
it's just that elegant code had the evolutionary advantage when it
came to populating correct-code-space.

For example Willem's (and Eric's?) needs_deleting() loop earlier is
such an elegant snippet, you can almost view it as an atomic whole
and see instantly if it's been done correctly or not.

I may be jabbering nonsense here, contrary views are welcome.
Phil
--
The list of trusted root authorities in your browser included the
United Arab Emirates-based Etisalat, which was caught secretly
uploading spyware onto 100,000 customers' BlackBerries.
http://www.wired.com/threatlevel/2009/07/blackberry-spies/

Phil Carmody

unread,
Dec 29, 2013, 11:34:03 AM12/29/13
to
James Kuyper <james...@verizon.net> writes:
> On 12/27/2013 02:14 AM, Matt wrote:
> > I'm sure I've read somewhere that it's considered bad practice to modify
> > the value of the variable on the right of a comparison operator inside
> > the loop concerned.
>
> The validity of that guideline depends upon what you're doing. For
> instance, if a loop starts with
>
> for(int item=0; item < item_count; item++)
>
> then it is potentially very confusing to change either item or
> item_count within the loop. That doesn't mean you shouldn't do it - if
> there's sufficiently good reason so do so, then you should; but you
> should draw attention to the lines where you perform the modification by
> inserting comments.

Sometimes even variable names can be enough of a clue, but yes, that
single line is enough of an idiom that it carries a lot of baggage about
what one would expect to follow.

> On the other hand, I've written code to do a bracketed binary search of
> a sorted array like the following:
>
> while(low < high)
> {
> int mid = (low+high)/2;
> if(array[mid] < x)
> low = mid+1;
> else
> high = mid;
> }
>
> The fact that this code modifies both "low" and "high" inside the loop
> is not a problem, because it's very clear why and how it's modifying them.

I notice that one example was a for() and the other was a while().
I'm a great believer that people over-use for() - I hate seeing ``; )'',
for example. That immediately says "should have been implemented as a
while loop" to me. My expectations are different from the two constructs
certainly.

Phil Carmody

unread,
Dec 29, 2013, 11:41:31 AM12/29/13
to
Dr Nick <nosp...@temporary-address.org.uk> writes:
> Ben Bacarisse <ben.u...@bsb.me.uk> writes:
>
> > Matt <ma...@clickertraining.co.nz> writes:
> >
> >> On 28/12/13 20:19, Ben Bacarisse wrote:
> >>> you have a redundant loop in
> >>> getscore which is the time-limiting function right now. You can count
> >>> the matching colours without looping over colours.
> >>
> >> http://code.mattsmith.org.nz/mastermind/bits/new_get_score.c
> >>
> >> I still iterated through colors once to set some stuff to 0.
> >
> > You can use '= {0};' as the initialiser to zero the arrays.
>
> I've not checked to see if it's still the case, but one of the most
> irritating features of GCC that I've come across is that it warns that
> this is not a complete initiator.
>
> Now if I've done = {1,2,3,4,5,6} for a 7 element array, I may well not
> want the last initialised to 0, so I can understand the warning. But =
> {0} should be a special case.

If we're hypothesising, then why not have the default zero initialiser
syntax be = {}; ? 2 initialisers is some. 1 initialiser is some. 0
initialisers is none. If isolating a special case, surely the one that
stands on its own (none, vs. some) is the best one to choose?

> Of course, you can always turn off warnings etc, but this particular one
> seemed especially irritating.

I have a few "favourites" which I like less.

Seebs

unread,
Dec 29, 2013, 1:49:18 PM12/29/13
to
On 2013-12-29, Eric Sosman <eso...@comcast-dot-net.invalid> wrote:
> I think that "elegance" means different things to the two
> of us (eye of the beholder, again). The quality you describe
> as "elegance" is something I'd prefer to call "clarity," and I
> agree that it's a desirable attribute regardless of whether you
> call it clarigance or eleganity.

Hmm. You may have a point.

> ... and that's why I don't think "elegance" is a useful
> criterion: If you can't measure it, you can't tell whether it's
> present or absent, or to what degree.

I'm not sure that's right. Or rather: Even if things are subjective,
they may still be useful criteria. They may be observer-variant, but I
would tend to consider "pleasant to work on" a significant trait to
consider when evaluating prospective projects.

> [*] IIRC, Weinberg reported on a similar experiment in "The
> Psychology of Computer Programming." Groups of computer science
> students read the same piece of code, either in its original form
> or with the comments removed. The students who saw the UNcommented
> code found and fixed more of its errors than those who had the
> "benefit" of the commentary ...

That's not surprising. Comments that tell you what's supposed to happen
are likely to make you expect that to be what happens.

I usually aim comments at explaining why I do something unexpected
that took a while to figure out. Otherwise, code is usually pretty
comprehensible if it's reasonably clear.

Nick Bowler

unread,
Dec 30, 2013, 2:15:19 AM12/30/13
to
On Sun, 29 Dec 2013 13:46:34 +0000, Dr Nick wrote:
> Ben Bacarisse <ben.u...@bsb.me.uk> writes:
>> You can use '= {0};' as the initialiser to zero the arrays.
>
> I've not checked to see if it's still the case, but one of the most
> irritating features of GCC that I've come across is that it warns that
> this is not a complete initiator.
>
> Now if I've done = {1,2,3,4,5,6} for a 7 element array, I may well not
> want the last initialised to 0, so I can understand the warning. But =
> {0} should be a special case.
>
> Of course, you can always turn off warnings etc, but this particular one
> seemed especially irritating.

That particular warning is not enabled by default so you can simply,
well, not enable it. I guess that's sort of like turning it off.

Kenny McCormack

unread,
Dec 30, 2013, 5:03:48 AM12/30/13
to
In article <l9pebv$s9s$1...@dont-email.me>,
Eric Sosman <eso...@comcast-dot-net.invalid> wrote:
...
> I think that "elegance" means different things to the two
>of us (eye of the beholder, again). The quality you describe
>as "elegance" is something I'd prefer to call "clarity," and I
>agree that it's a desirable attribute regardless of whether you
>call it clarigance or eleganity.

Interestingly enough, the actual, original definition of "elegant" is
"minimalist". Which, in the context of the religion of CLC, ends up
meaning exactly the opposite of "clarity" (since "clarity" usually ends up
meaning "be as verbose as possible").

--
The problem in US politics today is that it is no longer a Right/Left
thing, or a Conservative/Liberal thing, or even a Republican/Democrat
thing, but rather an Insane/not-Insane thing.

(And no, there's no way you can spin this into any confusion about
who's who...)

Aleksandar Kuktin

unread,
Dec 30, 2013, 10:40:25 AM12/30/13
to
On Sat, 28 Dec 2013 11:30:21 -0500, Eric Sosman wrote:

> Finally, to your "backtracking counter" loop: I really,
> really don't like it. A better formulation, I think, would be
>
> for (i = 0; i < len; ) {
> if (needs_deleting(arr[i])
> len = del_at(i, len, arr);
> else
> ++i;
> }
>
> ... because the reader will not be fooled by the familiar-looking `i++'
> in the first line and perhaps overlook the unfamiliar in-loop
> adjustment. Seeing no index adjustment at all in the `for', he will
> look inside the loop to learn what happens to `i', and (I think) his
> route to understanding will be a shorter one.

See, that's *exactly* the kind of response I was looking for. It teaches
me an alternative way of doing things I myself had doubts about when
doing them the way I did them.

As to the 'elegance' discussion, I though for a while what word to use
and basically chose 'elegance' over others because I thought it had the
higest chance of conveying the intended meaning and producing the desired
response. The fact I got the response I wished for basically proves my
choice right. :)

Matt

unread,
Dec 30, 2013, 4:30:30 PM12/30/13
to
On 29/12/13 21:58, Matt wrote:
> On 28/12/13 20:19, Ben Bacarisse wrote:
>> you have a redundant loop in
>> getscore which is the time-limiting function right now. You can count
>> the matching colours without looping over colours.
>
> http://code.mattsmith.org.nz/mastermind/bits/new_get_score.c

I plugged the new getscore in to the apple][ code and got a performance
gain. 15min wait on the first pass vs 20min previously.

I think I discovered something else though.

Looking at a single conceptually boolean int to see whether it is
necessary to do something to something seems like a trivial operation.

What if you did it 1296 * (15 * 1296) times and only 1296 * (1 * 1296)
of them were necessary? Could this slow your program down?

If anyone is curious the offending code is the loop at line 178 of
http://code.mattsmith.org.nz/mastermind/aztecc65/main.c

I think Eric was on the money when he said

> I suspect something's
> seriously amiss with your setup

And I was on the money when I said

> I'm pretty sure it'll turn out to be my program

Matt.

Jorgen Grahn

unread,
Dec 30, 2013, 5:19:07 PM12/30/13
to
It's also terribly ugly, IMO. "The cure is worse than the disease" is
a phrase which comes to mind. A big part of the appeal of for loops
is "look, here's all you have to know about how 'i' changes, in one
single line".

(I don't think I've seem it before, except of course the form with an
explicit "please stop the loop" flag -- 'i < len && !stop')

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Eric Sosman

unread,
Dec 30, 2013, 6:11:59 PM12/30/13
to
On 12/30/2013 4:30 PM, Matt wrote:
> On 29/12/13 21:58, Matt wrote:
>> On 28/12/13 20:19, Ben Bacarisse wrote:
>>> you have a redundant loop in
>>> getscore which is the time-limiting function right now. You can count
>>> the matching colours without looping over colours.
>>
>> http://code.mattsmith.org.nz/mastermind/bits/new_get_score.c
>
> I plugged the new getscore in to the apple][ code and got a performance
> gain. 15min wait on the first pass vs 20min previously.

Still seems far too long. See below.

> I think I discovered something else though.
>
> Looking at a single conceptually boolean int to see whether it is
> necessary to do something to something seems like a trivial operation.
>
> What if you did it 1296 * (15 * 1296) times and only 1296 * (1 * 1296)
> of them were necessary? Could this slow your program down?

If you drank fifteen times your normal intake of beer,
could this slow *you* down? ;-)

Might this account for your fifteen minutes? Let's use the
back of this handy envelope here: 25e6 tests divided by 900 seconds
is 28000 tests/sec, or 36 microseconds/test. You've mentioned that
you're using an emulator for an elderly machine, and "36 MHz" might
be in the right ballpark. If the host machine's instruction set is
dissimilar to that of the emulated system, the emulator may well
be an interpreter; such things often execute dozens to hundreds
of host instructions for each emulated instruction. If the test
and branch amounts to four or five emulated instructions, a twenty-
fold dilation would turn "36 MHz" into "3 or so GHz," which would
be something akin to what one would get from a present-day machine.

Of course, this doesn't *prove* the extra work is soaking up
all or even most of your time, but the numbers seem plausible and
do not rule out the possibility. I think you'd do well to give
this matter further attention.

--
Eric Sosman
eso...@comcast-dot-net.invalid

Jorgen Grahn

unread,
Dec 30, 2013, 6:26:47 PM12/30/13
to
On Sun, 2013-12-29, Phil Carmody wrote:
...
> I notice that one example was a for() and the other was a while().
> I'm a great believer that people over-use for() - I hate seeing ``; )'',
> for example.

Me too, but I don't seem to see it a lot. My feeling is people abused
for() more in the past, perhaps because the optimizers were worse.

> That immediately says "should have been implemented as a
> while loop" to me.

Yes. 'for' is IMHO good for a few (but common!) cases only.

Jorgen Grahn

unread,
Dec 31, 2013, 4:50:56 AM12/31/13
to
On Sun, 2013-12-29, Seebs wrote:
> On 2013-12-29, Eric Sosman <eso...@comcast-dot-net.invalid> wrote:
>> I think that "elegance" means different things to the two
>> of us (eye of the beholder, again). The quality you describe
>> as "elegance" is something I'd prefer to call "clarity," and I
>> agree that it's a desirable attribute regardless of whether you
>> call it clarigance or eleganity.
>
> Hmm. You may have a point.
>
>> ... and that's why I don't think "elegance" is a useful
>> criterion: If you can't measure it, you can't tell whether it's
>> present or absent, or to what degree.
>
> I'm not sure that's right. Or rather: Even if things are subjective,
> they may still be useful criteria.

Yes. (Also, even the interesting properties you /can/ measure are
usually infeasible to measure. You won't have a team of psychologists
and a study group handy when it's time for code review ...)

Almost all conflicts I have with coworkers, people on Usenet, previous
authors of code I have to maintain, etc ... are about subjective
things. E.g. the code is reasonably correct, but it's not as easy
(pleasant) to work with as I'd like it.

Frustratingly, too often (most of the time, it seems) what's readable
to one person is not very readable to all others. Only the people who
just don't care are unaffected.

Clarity as a concept doesn't seem a lot more helpful. Your background
and way of thinking has too much of an impact on what you see as
"clear".

Eric Sosman

unread,
Dec 31, 2013, 8:21:37 AM12/31/13
to
On 12/30/2013 6:11 PM, Eric Sosman wrote:
> On 12/30/2013 4:30 PM, Matt wrote:
>> On 29/12/13 21:58, Matt wrote:
>>> On 28/12/13 20:19, Ben Bacarisse wrote:
>>>> you have a redundant loop in
>>>> getscore which is the time-limiting function right now. You can count
>>>> the matching colours without looping over colours.
>>>
>>> http://code.mattsmith.org.nz/mastermind/bits/new_get_score.c
>>
>> I plugged the new getscore in to the apple][ code and got a performance
>> gain. 15min wait on the first pass vs 20min previously.
>
> Still seems far too long. See below.
>
>> I think I discovered something else though.
>>
>> Looking at a single conceptually boolean int to see whether it is
>> necessary to do something to something seems like a trivial operation.
>>
>> What if you did it 1296 * (15 * 1296) times and only 1296 * (1 * 1296)
>> of them were necessary? Could this slow your program down?
>
> If you drank fifteen times your normal intake of beer,
> could this slow *you* down? ;-)
>
> Might this account for your fifteen minutes? Let's use the
> back of this handy envelope here: 25e6 tests divided by 900 seconds
> is 28000 tests/sec, or 36 microseconds/test. You've mentioned that
> you're using an emulator for an elderly machine, and "36 MHz" might
> be in the right ballpark. [...]

Botch. Botch, botch, botchety-botch-botch-botch.

"Hold it right there, fella. Put down the pencil, and step
away from the envelope. Okay, let's see your estimating license.
No, take it out of your wallet first, that's right. Well, well,
what have we here? Estimating with a suspended license? Don't
explain to me; save it for the judge. You have the right to
remain silent, ..."

"Honestly, Your Honor, I don't know what came over me. The
cat was trying to get my attention and maybe that distracted me,
but I still don't know why I pushed one-over-ex after calculating
a rate, and then called *that* a rate, and mangled the units, too.
28000 tests/sec has nothing to do with `36 MHz' -- it's 28 kHz or
0.028 MHz, as any fool can plainly see. No offense, Your Honor.
And all that stuff about a hundredfold slowdown explaining the
difference between `36 MHz' and a modern machine -- well, it's
completely off the mark, I see that now. It'd take something like
a hundred-thousand-fold slowdown to cover the actual discrepancy,
and that's more than I'd like to believe in. It'd still be good
for him to figure out why he's doing fifteen times as much work as
necessary, but that in itself won't account for his time."

"No, Your Honor, I don't hold a grudge against him -- I don't
even know him. I certainly wasn't trying to make trouble for him,
I just blundered, that's all. Nothing malicious, just a thinko."

"Uh, no, it's not my first offense. My worst, maybe, but not
my first. How many? Well, in four-plus decades of estimating I
must have-- Oh, right, sorry: With a suspended license, I shouldn't
be trying to estimate how many estimations I've mis-estimated. All
I can say is that there was no ill will, and that I'll be more
careful in the future, and I plead for the Court's understanding."

--
Eric Sosman
eso...@comcast-dot-net.invalid

glen herrmannsfeldt

unread,
Dec 31, 2013, 6:50:58 PM12/31/13
to
Eric Sosman <eso...@comcast-dot-net.invalid> wrote:
> On 12/30/2013 6:11 PM, Eric Sosman wrote:
(snip)
>> If you drank fifteen times your normal intake of beer,
>> could this slow *you* down? ;-)

(snip)

> Botch. Botch, botch, botchety-botch-botch-botch.

> "Hold it right there, fella. Put down the pencil, and step
> away from the envelope. Okay, let's see your estimating license.
> No, take it out of your wallet first, that's right. Well, well,
> what have we here? Estimating with a suspended license? Don't
> explain to me; save it for the judge. You have the right to
> remain silent, ..."

> "Honestly, Your Honor, I don't know what came over me. The
> cat was trying to get my attention and maybe that distracted me,
> but I still don't know why I pushed one-over-ex after calculating
> a rate, and then called *that* a rate, and mangled the units, too.
> 28000 tests/sec has nothing to do with `36 MHz' -- it's 28 kHz or
> 0.028 MHz, as any fool can plainly see.

Reminds me how often 1/x is misapplied. Resolution should be in
spatial frequency (something per unit distance) not distance
units. Otherwise "high resolution" has the wrong meaning.

More intersting is shutter speed on cameras, which should be
in reciprocal time units. That is, not (1/125) second, but
125/second. (Which nicely agrees with the labels on the
shutter speed dial, but not with the common description.)
Again, high shutter speed needs to have the right meaning.

Yes, the one-over-ex key gets pressed too often.

> No offense, Your Honor.
> And all that stuff about a hundredfold slowdown explaining the
> difference between `36 MHz' and a modern machine -- well, it's
> completely off the mark, I see that now. It'd take something like
> a hundred-thousand-fold slowdown to cover the actual discrepancy,
> and that's more than I'd like to believe in. It'd still be good
> for him to figure out why he's doing fifteen times as much work as
> necessary, but that in itself won't account for his time."

(snip, really funny, too)

-- glen

Richard

unread,
Jan 1, 2014, 10:55:12 AM1/1/14
to
gaz...@shell.xmission.com (Kenny McCormack) writes:

> In article <l9pebv$s9s$1...@dont-email.me>,
> Eric Sosman <eso...@comcast-dot-net.invalid> wrote:
> ...
>> I think that "elegance" means different things to the two
>>of us (eye of the beholder, again). The quality you describe
>>as "elegance" is something I'd prefer to call "clarity," and I
>>agree that it's a desirable attribute regardless of whether you
>>call it clarigance or eleganity.
>
> Interestingly enough, the actual, original definition of "elegant" is
> "minimalist". Which, in the context of the religion of CLC, ends up
> meaning exactly the opposite of "clarity" (since "clarity" usually ends up
> meaning "be as verbose as possible").

It depends if you know C or not.

One moron I had the displeasure of working with decided that something
like

while(*d++=*s++);

was not "clear" and needed to be expanded with long ariable names and to
use array notation and an exploded loop.

I pointed out that any C programmer that didn't understand that code
had no right being in the team since its "bread ad butter" for any half
decent C programmer.

The above is both elegant and exhibits clarity IMO. Had it been C++ that
would not be the case for obvious reasons... ;)

--
"Avoid hyperbole at all costs, its the most destructive argument on
the planet" - Mark McIntyre in comp.lang.c

Ben Bacarisse

unread,
Jan 1, 2014, 11:25:58 AM1/1/14
to
glen herrmannsfeldt <g...@ugcs.caltech.edu> writes:
<snip>
> More intersting is shutter speed on cameras, which should be
> in reciprocal time units. That is, not (1/125) second, but
> 125/second. (Which nicely agrees with the labels on the
> shutter speed dial, but not with the common description.)
> Again, high shutter speed needs to have the right meaning.

It does. I think you are confusing exposure time with shutter speed. A
high shutter speed is exactly that -- a shutter moving very fast, giving
rise to a very short exposure time.

<snip>
--
Ben.

glen herrmannsfeldt

unread,
Jan 1, 2014, 3:34:10 PM1/1/14
to
Ben Bacarisse <ben.u...@bsb.me.uk> wrote:

(snip, I wrote)
>> More intersting is shutter speed on cameras, which should be
>> in reciprocal time units. That is, not (1/125) second, but
>> 125/second. (Which nicely agrees with the labels on the
>> shutter speed dial, but not with the common description.)
>> Again, high shutter speed needs to have the right meaning.

> It does. I think you are confusing exposure time with shutter speed.
> A high shutter speed is exactly that -- a shutter moving very fast,
> giving rise to a very short exposure time.

As with the post I replied to, some people put 1/x where it isn't
needed or wanted.

Often people will write shutter speed = (value with time units),
where it comes out right for (value with reciprocal time units.)

-- glen

Matt

unread,
Jan 1, 2014, 4:13:10 PM1/1/14
to
On 01/01/14 02:21, Eric Sosman wrote:
> It'd still be good
> for him to figure out why he's doing fifteen times as much work as
> necessary, but that in itself won't account for his time."

Wrapping up my participation in this thread:

Because constantly rejigging my gcc code for the old compiler was
tedious I ended up using the time taken for the gcc code to solve all
1296 possible codes as a proxy for speed/efficiency/whatever, assuming
any gains made would also manifest when I later rewrote for the 6502
cross compiler.

At one point I got a dramatic improvement:

>----<
$ cat *w/time
[...]01//a working version of the code
1295 K3

real 20m43.325s
user 20m43.142s
sys 0m0.048s

[...]05//the next working version (02, 03, 04 all broken or still born)
1295 K3

real 7m13.622s
user 7m13.563s
sys 0m0.004s
>----<

Because I would get fed up and start a wholesale rewrite in a new
directory it's a little difficult to pin down exactly what was
responsible for the improvement but here are some changes between the
versions:

1. getscore function rewritten per Ben's advice.
2. I stole Willem's loop (I really like that loop!). This had the effect
of fixing the 15 times too much work thing I'm pretty sure.
3. Fewer functions.
4. Fewer structs appearing in parameter lists. More use of indexes then
looking up the code later.

But as for the single silver bullet I'd have to go back over it all to
find out for sure.

The improvement didn't really manifest in the 6502 version. Or it did
but only after the first pass through the algorithm which still takes 13
min. Weird. I've taken this over to comp.sys.apple2.programmer

So I learned some things:

Thing: If you break your code into lots of tiny functions you can end up
seeing too many trees and not enough of the woods.

Thing: If every time you change your code, you break it then maybe you
had a tenuous or incomplete understanding of the algorithm to begin with.

Thing: Modern implementations like gcc are a huge advance on what was
available for the Apple //e in 1986.

Thanks to all responders,

Matt.



Robert Wessel

unread,
Jan 1, 2014, 8:05:07 PM1/1/14
to
It's actually not.

Shutters on cameras almost always are of a two curtain design, and
almost always the curtains move at a fixed speed. The second
(closing) curtain follows the opening one at the specified interval.
For a longer exposure (slower than the flash sync speed), the first
curtain opens fully before the second curtain starts to move (and
close the opening). But even then, since the curtain speed in finite,
one edge will be exposed somewhat earlier than the other edge,
although with modest exposure speeds it's pretty much a non-issue,
since motion blur will almost always far overshadow any position
changes in the subject.

With high shutter speeds, the curtains continue to move at the same
speed, but the closing one starts moving before the opening one
finishes opening. Thus there's a (moving) open slit. The width of
the moving slit then defines the exposure time, and the faster
exposure time you set, the narrower the slit (while the slit is still
moving at the same speed). This can lead to interesting effects as
one edge of the picture is fully exposed long before the other edge.
People photographic flying helicopters, for example, have to be
careful not to select a shutter speed that results in (apparently)
curved rotor blades.

Flash sync speed is important since the flash can only go off when the
shutter is fully open (IOW, the opening curtain has finished its
travel, and the closing curtain has not yet started) or only the open
part of the frame will see the flash. Better cameras do have faster
shutter curtains, which enables faster sync speeds (it also enables
higher "slit" shutter speeds, since it allows you to have reasonable
width slits at the higher speeds).

And just for completeness, a few cameras do have variable speed
shutter curtains, but the lower speeds are only selected to reduce
noise and/or power consumption.

Kenny McCormack

unread,
Jan 2, 2014, 4:58:31 AM1/2/14
to
In article <87lhyzv...@gmail.com>, Richard <rgr...@gmail.com> wrote:
>gaz...@shell.xmission.com (Kenny McCormack) writes:
>
>> In article <l9pebv$s9s$1...@dont-email.me>,
>> Eric Sosman <eso...@comcast-dot-net.invalid> wrote:
>> ...
>>> I think that "elegance" means different things to the two
>>>of us (eye of the beholder, again). The quality you describe
>>>as "elegance" is something I'd prefer to call "clarity," and I
>>>agree that it's a desirable attribute regardless of whether you
>>>call it clarigance or eleganity.
>>
>> Interestingly enough, the actual, original definition of "elegant" is
>> "minimalist". Which, in the context of the religion of CLC, ends up
>> meaning exactly the opposite of "clarity" (since "clarity" usually ends up
>> meaning "be as verbose as possible").
>
>It depends if you know C or not.
>
>One moron I had the displeasure of working with decided that something
>like
>
>while(*d++=*s++);
>
>was not "clear" and needed to be expanded with long ariable names and to
>use array notation and an exploded loop.
>
>I pointed out that any C programmer that didn't understand that code
>had no right being in the team since its "bread ad butter" for any half
>decent C programmer.

I'd be willing to assert that for most working C programmers today, the
above code is (pick all that apply): strange, cryptic, weird, "clever", not
"clear", etc, etc, and that an explicit form with a loop would be much
better in their eyes.

Because, as is true of just about every population, most working C
programmers today are idiots. It's what managememnt wants.

--
The scent of awk programmers is a lot more attractive to women than
the scent of perl programmers.

(Mike Brennan, quoted in the "GAWK" manual)

Aleksandar Kuktin

unread,
Jan 2, 2014, 9:05:05 AM1/2/14
to
On Wed, 01 Jan 2014 16:55:12 +0100, Richard wrote:

> while(*d++=*s++);

Excuse me, but.... how is this loop supposed to stop. Exactly?


I assume it was meant to be something more akin to

while (*d++ == *s++);

but that the other `=' got lost somewhere.

Martin Shobe

unread,
Jan 2, 2014, 9:08:44 AM1/2/14
to
On 1/2/2014 8:05 AM, Aleksandar Kuktin wrote:
> On Wed, 01 Jan 2014 16:55:12 +0100, Richard wrote:
>
>> while(*d++=*s++);
>
> Excuse me, but.... how is this loop supposed to stop. Exactly?
>

It stops when *d++ = *s++ is equal to zero. In other words, when s
points to a zero value. It does copy the zero.

Martin Shobe


James Kuyper

unread,
Jan 2, 2014, 11:20:43 AM1/2/14
to
On 01/02/2014 09:05 AM, Aleksandar Kuktin wrote:
> On Wed, 01 Jan 2014 16:55:12 +0100, Richard wrote:
>
>> while(*d++=*s++);
>
> Excuse me, but.... how is this loop supposed to stop. Exactly?

This is something I've always considered to be one of the basic idioms
of C, which is discussed in some detail in K&R. I understood that
discussion on first reading. Over several decades, I've learned that I
must be fairly unusual in that regard - most of the C programmers I've
challenged to provide a detailed explanation of how that construct works
were unable to do so, so don't feel too embarrassed about not having
understood it.

That construct presents several tricky issues, starting with the
question of which gets evaluated first, the * or the ++. The next issue
is precisely which value is returned by the ++ expression. The next
issue is what the value of an assignment expression is. Once you've
thought through those issues, you should be ready to answer the key
question: under what circumstances is the value of the expression
*d++=*s++ equal to zero? Those are precisely the circumstances that will
cause the while loop to terminate.

Geoff

unread,
Jan 2, 2014, 11:35:47 AM1/2/14
to
And here we have the lesson in why the code, while correct and
succinct, is easily misunderstood to be "strange". One has to stop and
say, "er, what?".

Keith Thompson

unread,
Jan 2, 2014, 11:41:05 AM1/2/14
to
An assignment yields the value that was assigned. That value
is the condition tested by the "while".

It's a bit terse for my own taste, but it's well defined and a common C
idiom.

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

christ...@cbau.wanadoo.co.uk

unread,
Jan 2, 2014, 12:04:27 PM1/2/14
to
On Wednesday, January 1, 2014 3:55:12 PM UTC, Richard wrote:

> One moron I had the displeasure of working with decided that something
> like
>
> while(*d++=*s++);
>
> was not "clear" and needed to be expanded with long ariable names and to
> use array notation and an exploded loop.
>
> I pointed out that any C programmer that didn't understand that code
> had no right being in the team since its "bread ad butter" for any half
> decent C programmer.

1. Calling strcpy is a lot clearer and most likely more efficient if these are char*.
2. It is quite obvious what the code does. It is much less obvious what the programmer wanted it to do.
3. Adding space characters doesn't make it run any slower.
4. It wouldn't pass a code review where I work because it doesn't even compile. Two warnings, and warnings = error in all projects.
5. Calling a co-worker "moron" is a serious problem.

christ...@cbau.wanadoo.co.uk

unread,
Jan 2, 2014, 12:10:46 PM1/2/14
to
On Thursday, January 2, 2014 4:20:43 PM UTC, James Kuyper wrote:

> That construct presents several tricky issues, starting with the
> question of which gets evaluated first, the * or the ++. The next issue
> is precisely which value is returned by the ++ expression.

For example, if d is a pointer to unsigned 8 bit char, s is a pointer to unsigned int, and *s equals 256. It assigns 256 but ends up storing 0. How much would people be willing to bet on whether the loop ends or not, without checking a copy of the C Standard? And how much would people be willing to bet that this is the behaviour that the programmer intended?

James Kuyper

unread,
Jan 2, 2014, 12:34:49 PM1/2/14
to
On 01/02/2014 12:04 PM, christ...@cbau.wanadoo.co.uk wrote:
> On Wednesday, January 1, 2014 3:55:12 PM UTC, Richard wrote:
>
>> One moron I had the displeasure of working with decided that something
>> like
>>
>> while(*d++=*s++);
>>
>> was not "clear" and needed to be expanded with long ariable names and to
>> use array notation and an exploded loop.
>>
>> I pointed out that any C programmer that didn't understand that code
>> had no right being in the team since its "bread ad butter" for any half
>> decent C programmer.
>
> 1. Calling strcpy is a lot clearer and most likely more efficient if these are char*.

If you need the value of either s or d after the loop has executed,
which is not a particularly uncommon need, the loop is better than a
call to strcpy(), and some modern compilers can optimize it almost as
much as strcpy() itself.

> 2. It is quite obvious what the code does. ...

I've met quite a few C programmers who couldn't answer that question,
and most of the ones who could were unable to explain why it works.

> ... It is much less obvious what the programmer wanted it to do.

True: dropping an '=' is easier than accidentally typing strcmp() when
you meant strcpy() (but I have in fact seen that done).

> 4. It wouldn't pass a code review where I work because it doesn't even compile. Two warnings, and warnings = error in all projects.

I only get one warning, about the use of = in a context where == might
have been meant - what's the other warning?
I have some sympathy with the idea of treating warnings as if they were
errors, but a certain amount of judgement is needed, too. A compiler is
free to warn about anything it wants - for instance, the use of a
obscene word as an identifier (or even the failure to use obscene words
as identifiers).

> 5. Calling a co-worker "moron" is a serious problem.

Agreed - even if the co-worker is in fact a moron, there's better ways
to deal with that fact.

James Kuyper

unread,
Jan 2, 2014, 1:07:24 PM1/2/14
to
"An assignment expression has the value of the left operand after the
assignment" (6.5.16p1); since that value is 0, it will terminate. That
seems perfectly clear and obvious to me, but then I'm an expert in such
things - I can't objectively assess how obvious it might be to less
experienced programmers.

Aleksandar Kuktin

unread,
Jan 2, 2014, 1:42:04 PM1/2/14
to
On Thu, 02 Jan 2014 08:41:05 -0800, Keith Thompson wrote:

> Aleksandar Kuktin <aku...@gmail.com> writes:
>> On Wed, 01 Jan 2014 16:55:12 +0100, Richard wrote:
>>> while(*d++=*s++);
>>
>> Excuse me, but.... how is this loop supposed to stop. Exactly?
>>
>> I assume it was meant to be something more akin to
>>
>> while (*d++ == *s++);
>>
>> but that the other `=' got lost somewhere.
>
> An assignment yields the value that was assigned. That value is the
> condition tested by the "while".
>
> It's a bit terse for my own taste, but it's well defined and a common C
> idiom.

*OH* *MY* *GOD*!! WHAT THE FUCK! Jesus merciful Christ! Wow! Talk about
the suprise factor. *Completely* sailed over my head. Really cool. Were
it not as beautiful as it is, I would call it an eldritch abomination.

But you know what is the funniest thing in all this?

I am actually well informed of the "assigment return value" (to use a bit
LISPy terminology), and have, infact, used it without thinking twice
about it, like in this function call...

fill_32field((recursion ? (listento = get_nbnsaddr(scope)) :
(listento = 0, brdcst_addr)),
(unsigned char *)&(addr.sin_addr.s_addr));

...it's just that that `while' up there confused me. I have developed a
reflex to never use a naked assigment operator in tests, in order to
avoid the notorious "assignment when you meant test equality" bug, and
that reflex kicked in when I saw the code snippet.

Keith Thompson

unread,
Jan 2, 2014, 2:34:00 PM1/2/14
to
James Kuyper <james...@verizon.net> writes:
> On 01/02/2014 12:04 PM, christ...@cbau.wanadoo.co.uk wrote:
>> On Wednesday, January 1, 2014 3:55:12 PM UTC, Richard wrote:
>>> One moron I had the displeasure of working with decided that something
>>> like
>>>
>>> while(*d++=*s++);
>>>
>>> was not "clear" and needed to be expanded with long ariable names and to
>>> use array notation and an exploded loop.
>>>
>>> I pointed out that any C programmer that didn't understand that code
>>> had no right being in the team since its "bread ad butter" for any half
>>> decent C programmer.
>>
>> 1. Calling strcpy is a lot clearer and most likely more efficient if these are char*.
>
> If you need the value of either s or d after the loop has executed,
> which is not a particularly uncommon need, the loop is better than a
> call to strcpy(), and some modern compilers can optimize it almost as
> much as strcpy() itself.

Or you can use the non-standard strlcpy() if you happen to have it (and
your coding standards permit it). It returns the total length of the
string it tried to create, as a size_t; you can add that to the base
address to get a pointer to the end of the string.

glen herrmannsfeldt

unread,
Jan 2, 2014, 4:00:27 PM1/2/14
to
James Kuyper <james...@verizon.net> wrote:

(snip)
>> 4. It wouldn't pass a code review where I work because it
>> doesn't even compile. Two warnings, and warnings = error
>> in all projects.

With the tendency of compiler writers to add more and more
warnings, justified or not, I don't believe in the requirement
to code without warnings.

> I only get one warning, about the use of = in a context
> where == might have been meant - what's the other warning?
> I have some sympathy with the idea of treating warnings as
> if they were errors, but a certain amount of judgement is needed,
> too. A compiler is free to warn about anything it wants - for
> instance, the use of a obscene word as an identifier
> (or even the failure to use obscene words as identifiers).

There was a story many years ago about a school that had a
compiler that would refuse to compile programs with obscene words
in them, I believe even in comments. The students then figured out
how to write them vertically, such that the compiler didn't notice.

Also, another story about obscene words added in lower case, on
a system where the printer ignored lower case characters. He was
caught after a new printer was installed.

-- glen

Joe keane

unread,
Jan 2, 2014, 4:04:26 PM1/2/14
to
In article <l9r6i6$ku8$1...@dont-email.me>,
Nick Bowler <nbo...@draconx.ca> wrote:
>That particular warning is not enabled by default so you can simply,
>well, not enable it. I guess that's sort of like turning it off.

How about this:

const char foo[6] = "abcdef";

glen herrmannsfeldt

unread,
Jan 2, 2014, 4:26:02 PM1/2/14
to
Perfectly legal to me, but I suppose some compilers will warn
about it. If you want the null terminator, you should:

const char foo[] = "abcdef";

instead. Or:

char *foo="abcdef";

(with or without const) which has a different meaning, but
sometimes is more useful.

-- glen


Keith Thompson

unread,
Jan 2, 2014, 4:43:02 PM1/2/14
to
What about it? What are you asking? (gcc 4.7.2 at least doesn't warn
about it with "-Wall -Wextra".)

christ...@cbau.wanadoo.co.uk

unread,
Jan 2, 2014, 7:37:01 PM1/2/14
to
On Thursday, January 2, 2014 5:34:49 PM UTC, James Kuyper wrote:
> I only get one warning, about the use of = in a context where == might
> have been meant - what's the other warning?

The second warning is about

while (xxx);

Single semicolon after the while condition without intervening white space is quite possibly a mistake. This one is most likely intentional:

while (xxx)
;

I'm currently using Clang for everything; there is a list of about 40 warnings that can be turned on/off, and there are maybe five that we have disabled because they warn about things that are indeed not justified. If I have to change

while (*d++=*s++);

to

while ((*d++ = *s++) != 0)
;

to avoid warnings that's fine with me. Note that once you have zero warnings and tell the compiler that warnings = errors, it does save you a lot of time because many trivial mistakes will indeed give warnings and are caught before you even try out the code for the first time.

About "an assignment expression has the value of the left operand after the assignment": The rule is clear, but you could easily imagine a language "alternative-C" where the rule is "an assignment expression has the value of the right operand before the assignment". It's rare that it makes a difference, but I think it is too subtle that I would accept code that relies on that tiny difference.

christ...@cbau.wanadoo.co.uk

unread,
Jan 2, 2014, 7:48:17 PM1/2/14
to
On Thursday, January 2, 2014 9:00:27 PM UTC, glen herrmannsfeldt wrote:

> There was a story many years ago about a school that had a
> compiler that would refuse to compile programs with obscene words
> in them, I believe even in comments. The students then figured out
> how to write them vertically, such that the compiler didn't notice.

I vaguely remember seeing a comment in the source code of a widely available C compiler that accused the members of the C Standard committe of drug abuse (I think it was in the scanner code handling trigraphs).

glen herrmannsfeldt

unread,
Jan 3, 2014, 1:16:39 AM1/3/14
to
christ...@cbau.wanadoo.co.uk wrote:

(snip)

> About "an assignment expression has the value of the left
> operand after the assignment": The rule is clear,
> but you could easily imagine a language "alternative-C"
> where the rule is "an assignment expression has the value
> of the right operand before the assignment". It's rare
> that it makes a difference, but I think it is too subtle
> that I would accept code that relies on that tiny difference.

PL/I multiple assignment is of the form:

A, B, C, D = 3;

Where I believe that the right hand side is assigned to all
the variables. Otherwise, = is both the relational operator
and also used for assignment statments (it is not an assignment
operator).

A=B=C;

will assign 1 or 0 (converted from '1'B or '0'B) to A,
depending on B equalling C, or not.

-- glen

Robert Wessel

unread,
Jan 3, 2014, 3:01:33 AM1/3/14
to
On Fri, 3 Jan 2014 06:16:39 +0000 (UTC), glen herrmannsfeldt
<g...@ugcs.caltech.edu> wrote:

>christ...@cbau.wanadoo.co.uk wrote:
>
>(snip)
>
>> About "an assignment expression has the value of the left
>> operand after the assignment": The rule is clear,
>> but you could easily imagine a language "alternative-C"
>> where the rule is "an assignment expression has the value
>> of the right operand before the assignment". It's rare
>> that it makes a difference, but I think it is too subtle
>> that I would accept code that relies on that tiny difference.
>
>PL/I multiple assignment is of the form:
>
> A, B, C, D = 3;
>
>Where I believe that the right hand side is assigned to all
>the variables.


That's correct for PL/I. It's usually described as being equivalent
to:

T=3;
A=T;
B=T;
C=T;

Algol is the same, although the syntax is different ("A := B:= C :=
D:= 3").

I believe that in languages supporting multiple assignment, the PL/I /
Algol behavior is much more common.

C/C++ is sort-of different, but it doesn't really have multiple
assignment at all, just that assignment has a slightly unusual side
effect which can be used to do something that *looks* like multiple
assignment. Still, someone coding "dbl = intgr = 3.7;" should
probably be assigning a good wrist slapping.

glen herrmannsfeldt

unread,
Jan 3, 2014, 3:29:41 AM1/3/14
to
Robert Wessel <robert...@yahoo.com> wrote:

(snip, I wrote)
>>PL/I multiple assignment is of the form:

>> A, B, C, D = 3;

>>Where I believe that the right hand side is assigned to all
>>the variables.

> That's correct for PL/I. It's usually described as being equivalent
> to:

> T=3;
> A=T;
> B=T;
> C=T;

In the case of an expression more complicated than 3, I suppose so.

> Algol is the same, although the syntax is different ("A := B:= C :=
> D:= 3").

> I believe that in languages supporting multiple assignment, the PL/I /
> Algol behavior is much more common.

> C/C++ is sort-of different, but it doesn't really have multiple
> assignment at all, just that assignment has a slightly unusual side
> effect which can be used to do something that *looks* like multiple
> assignment. Still, someone coding "dbl = intgr = 3.7;" should
> probably be assigning a good wrist slapping.

Well, someone coding

intgr=3.7;

probably should also get a wrist slapping.

In Java, it would be considered a narrowing conversion and
require a cast. That would also catch some of the others
mentioned in this thread.

-- glen

Rosario193

unread,
Jan 3, 2014, 4:44:31 AM1/3/14
to
On Wed, 01 Jan 2014 16:55:12 +0100, Richard wrote:


>while(*d++=*s++);

ok
what about: "for(;*d=*s; ++d, ++s);"?

Rosario193

unread,
Jan 3, 2014, 4:46:15 AM1/3/14
to
On Wed, 01 Jan 2014 16:55:12 +0100, Richard wrote:

>while(*d++=*s++);

a^=a |i==0#.e|j==0#.e
.1: al=*i|*j=al|a==0#.2|j+=1|jc .e|i+=1|jc .e|#.1
.2:

BartC

unread,
Jan 3, 2014, 6:10:18 AM1/3/14
to


"Robert Wessel" <robert...@yahoo.com> wrote in message
news:ncqcc9lsnbs7amis5...@4ax.com...
> On Fri, 3 Jan 2014 06:16:39 +0000 (UTC), glen herrmannsfeldt

>>PL/I multiple assignment is of the form:
>>
>> A, B, C, D = 3;

> That's correct for PL/I. It's usually described as being equivalent
> to:
>
> T=3;
> A=T;
> B=T;
> C=T;
>
> Algol is the same, although the syntax is different ("A := B:= C :=
> D:= 3").
>
> I believe that in languages supporting multiple assignment, the PL/I /
> Algol behavior is much more common.
>
> C/C++ is sort-of different, but it doesn't really have multiple
> assignment at all, just that assignment has a slightly unusual side
> effect which can be used to do something that *looks* like multiple
> assignment.

The above would be more like:

D=3;
C=D;
B=C;
A=B;

in C. And in all these cases, where A, B, C, D are different types, they can
all end up with different values anyway!

Also in: A=B=C=A, it would be quite possible for A to change (using
something
like your dbl:=intgr example).

I think only with dynamic typing, would A, B, C, D all be assigned exactly
the same value (in some languages, it's not even four separate copies of it,
they would all refer to the same actual data!).

--
Bartc

Ben Bacarisse

unread,
Jan 3, 2014, 6:37:37 AM1/3/14
to
It's different to the original, but my first reaction is why write this
as a for loop? There seems to be a tradition of "for abuse" in some
places:

while (*d = *s) ++d, ++s;

Equally, this could be called "comma abuse" so maybe, if you want the
alternate semantics, you might write it:

while (*d = *s) { ++d; ++s; }

--
Ben.

Tonton Th

unread,
Jan 3, 2014, 6:45:55 AM1/3/14
to
On 2014-01-02, Keith Thompson <ks...@mib.org> wrote:

> Or you can use the non-standard strlcpy() if you happen to have it (and
> your coding standards permit it). It returns the total length of the
> string it tried to create, as a size_t; you can add that to the base
> address to get a pointer to the end of the string.

A sharp message from Theo Deraadt about strlcxx :

http://marc.info/?l=openbsd-tech&m=138733933417096&w=2

--
http://la.buvette.org/photos/myrys/g/jz-jno-thsf.html

Aleksandar Kuktin

unread,
Jan 3, 2014, 7:52:20 AM1/3/14
to
On Thu, 02 Jan 2014 13:43:02 -0800, Keith Thompson wrote:

> j...@panix.com (Joe keane) writes:
>> In article <l9r6i6$ku8$1...@dont-email.me>,
>> Nick Bowler <nbo...@draconx.ca> wrote:
>>>That particular warning is not enabled by default so you can simply,
>>>well, not enable it. I guess that's sort of like turning it off.
>>
>> How about this:
>>
>> const char foo[6] = "abcdef";
>
> What about it? What are you asking? (gcc 4.7.2 at least doesn't warn
> about it with "-Wall -Wextra".)

No NULL terminator. String six chars long is stored in a buffer six chars
long.

Rosario193

unread,
Jan 3, 2014, 8:31:04 AM1/3/14
to
On Fri, 03 Jan 2014 11:37:37 +0000, Ben Bacarisse wrote:
>Rosario193 <Ros...@invalid.invalid> writes:
>> On Wed, 01 Jan 2014 16:55:12 +0100, Richard wrote:
>>
>>>while(*d++=*s++);
>>
>> ok
>> what about: "for(;*d=*s; ++d, ++s);"?
>
>It's different to the original,

the only difference i see it is for "for", d and s point to a \0 byte
at end

and in the while loop d and s poiunt at end one char afther \0 one

>but my first reaction is why write this
>as a for loop?

if someone want to use only "for loop" and never "while() loop", can
simplify a little the language [one word less in the language]

James Kuyper

unread,
Jan 3, 2014, 9:34:03 AM1/3/14
to
True - which might or might not be a problem, depending upon whether or
not the author intended that to be the case. Keith was probably well
aware of that - the question is, what was Joe's point in bringing that up?
--
James Kuyper

James Kuyper

unread,
Jan 3, 2014, 9:50:40 AM1/3/14
to
On 01/02/2014 07:37 PM, christ...@cbau.wanadoo.co.uk wrote:
> On Thursday, January 2, 2014 5:34:49 PM UTC, James Kuyper wrote:
>> I only get one warning, about the use of = in a context where == might
>> have been meant - what's the other warning?
>
> The second warning is about
>
> while (xxx);
>
> Single semicolon after the while condition without intervening white space is quite possibly a mistake. This one is most likely intentional:
>
> while (xxx)
> ;

Odd - I've used that construct occasionally, and I always wrote it the
first way, which seems more natural to me. My compiler doesn't warn
about that issue with the settings I use.

> I'm currently using Clang for everything; there is a list of about 40 warnings that can be turned on/off, and there are maybe five that we have disabled because they warn about things that are indeed not justified. If I have to change
>
> while (*d++=*s++);
>
> to
>
> while ((*d++ = *s++) != 0)

How do you decide when to stop adding !=0? All of the following mean the
same thing:

while (a)
while (a!=0)
while ((a!=0) !=0)
etc.

My policy is to stop adding !=0 before the first time.
--
James Kuyper

Aleksandar Kuktin

unread,
Jan 3, 2014, 11:03:17 AM1/3/14
to
Apologies - I'm too trigger happy for my own good.

I thought this is part of the str* discussion in the other part of the
thread. And, in that context, I assumed Joe was asking bringing up
something along the lines strlcpy vs. non-terminated string but, again, I
confused the discussion in which this series of posts appears.

Keith Thompson

unread,
Jan 3, 2014, 12:12:27 PM1/3/14
to
Yes, I know. BTW, NULL is (a macro that expands to) a null *pointer*
constant; it shouldn't be used to refer to the null character.

Aleksandar Kuktin

unread,
Jan 3, 2014, 12:14:18 PM1/3/14
to
On Fri, 03 Jan 2014 09:12:27 -0800, Keith Thompson wrote:

> Yes, I know. BTW, NULL is (a macro that expands to) a null *pointer*
> constant; it shouldn't be used to refer to the null character.

Sorry for the noise. Confused the discussion.

Keith Thompson

unread,
Jan 3, 2014, 12:28:46 PM1/3/14
to
My policy (not to imply that there's anything wrong with yours)
is to use an explicit comparison when the value being tested is not
"boolean", i.e., when it carries information beyond "zero is false,
non-zero is true". For example, I don't use a pointer value directly
as a condition; I'd write "if (ptr != NULL)" rather than "if (ptr)".

Ben Bacarisse

unread,
Jan 3, 2014, 3:18:14 PM1/3/14
to
James Kuyper <james...@verizon.net> writes:

> On 01/02/2014 07:37 PM, christ...@cbau.wanadoo.co.uk wrote:
>> [...] If I have to change
>>
>> while (*d++=*s++);
>>
>> to
>>
>> while ((*d++ = *s++) != 0)
>
> How do you decide when to stop adding !=0?

He stops there, because that form (apparently) silences a warning. The
explanation was in the immediately following text that got snipped: "If
I have to change ... to ... /to avoid warnings that's fine with me/.".

--
Ben.

James Kuyper

unread,
Jan 3, 2014, 3:47:48 PM1/3/14
to
Yes, but he also explaining that he was willing to turn off warnings
that he considered unjustified - implying that he considers this one
justified. I'm don't remember if my compiler has the option to warn
about such things, but if it did, I've turned it off. So my question was
equivalent to asking "why don't your turn that warning off?".
--
James Kuyper

glen herrmannsfeldt

unread,
Jan 3, 2014, 4:06:06 PM1/3/14
to
Aleksandar Kuktin <aku...@gmail.com> wrote:
> On Thu, 02 Jan 2014 13:43:02 -0800, Keith Thompson wrote:
>> j...@panix.com (Joe keane) writes:

(snip)
>>> How about this:

>>> const char foo[6] = "abcdef";

(snip)
> No NULL terminator. String six chars long is stored in a
> buffer six chars long.

No, not a string but six characters are stored there.

It is short for:

const char foo[6]={'a', 'b', 'c', 'd', 'e', 'f',};

which has many uses. (Among others, note that sizeof gives
the right size in both cases, but not if you add the null.)

If you really want the string, leave off the 6, the compiler will
count them for you, including the null. Compilers count better
than people do.

-- glen

christ...@cbau.wanadoo.co.uk

unread,
Jan 3, 2014, 7:06:08 PM1/3/14
to
On Friday, January 3, 2014 8:47:48 PM UTC, James Kuyper wrote:

> Yes, but he also explaining that he was willing to turn off warnings
> that he considered unjustified - implying that he considers this one
> justified. I'm don't remember if my compiler has the option to warn
> about such things, but if it did, I've turned it off. So my question was
> equivalent to asking "why don't your turn that warning off?".

Not turning on warnings for individual lines of code, but complete classes of warnings. And I don't enable a warning because the compiler allows me to turn the warning on, but because I think that the warning will often indicate a real problem in the code.

One of the warnings is for "result of assignment cannot be used as controlling expression of an if, for, or while statement". If you write "if (a = b)... " it is obviously not clear whether you meant it or meant to use "==". Several ways to tell the compiler "I meant it". One is to write "if ((a = b))...", another is "if ((a = b) != 0)...". The first one looks daft to me, so I use the second.

The second warning is to avoid code like

for (i = 0; i < n; ++i);
a [i] = 0;

or

if (x > 0);
++x;

which both most likely do _not_ do what the programmer intended.

And there are really two criteria for deciding which warnings to enable: (1) How likely is it if I get the warning that it is actually a bug in my code, and (2) how much of a pain is it to write code that avoids the warning when it is not justified. In the string copy loop, the change is quite trivial.

Clang and gcc have a few particularly annoying warnings. One is that

if (x >= MINIMUM_VALUE && x <= MAXIMUM_VALUE) ...

gives a warning if x is unsigned and MINIMUM_VALUE is 0.

A very annoying one is that

static struct some_struct x = { 0 };

gives a warning because not all struct members are initialised. " = { 0 }" is an obvious idiom for setting all elements to 0. Obviously if the struct has six elements and the initialiser has only five, that should give a warning because it is likely that an element was forgotten.

glen herrmannsfeldt

unread,
Jan 3, 2014, 10:03:08 PM1/3/14
to
christ...@cbau.wanadoo.co.uk wrote:

(snip)
> One of the warnings is for "result of assignment cannot be
> used as controlling expression of an if, for, or while statement".
> If you write "if (a = b)... " it is obviously not clear whether
> you meant it or meant to use "==". Several ways to tell the
> compiler "I meant it". One is to write "if ((a = b))...", another
> is "if ((a = b) != 0)...". The first one looks daft to me,
> so I use the second.

The wording doesn't sound like warning wording. "Cannot"
should be used for violations of the standard language.
Maybe "should not" or "preferably not" would be better.

> The second warning is to avoid code like

> for (i = 0; i < n; ++i);
> a [i] = 0;

> or

> if (x > 0);
> ++x;

> which both most likely do _not_ do what the programmer intended.

I usually put at least one space. I suppose some might use {}.

Since the above loop has no other effect than to set i equal to n,
unless n is negative, I wouldn't be against the warning.

If the loop has more useful side effects, though, I would rather
not have a warning.

I don't remember ever having made that mistake.

> And there are really two criteria for deciding which warnings
> to enable: (1) How likely is it if I get the warning that it
> is actually a bug in my code, and (2) how much of a pain is it
> to write code that avoids the warning when it is not justified.
> In the string copy loop, the change is quite trivial.

It is always cost vs. benefit. Reading warnings takes time,
and so has a cost. The cost, multiplied by its probability
should be balanced against the benefit, that is, the cost
and probability of missing the bug.

-- glen

Richard

unread,
Jan 4, 2014, 12:03:10 PM1/4/14
to
gaz...@shell.xmission.com (Kenny McCormack) writes:

> In article <87lhyzv...@gmail.com>, Richard <rgr...@gmail.com> wrote:
>>gaz...@shell.xmission.com (Kenny McCormack) writes:
>>
>>> In article <l9pebv$s9s$1...@dont-email.me>,
>>> Eric Sosman <eso...@comcast-dot-net.invalid> wrote:
>>> ...
>>>> I think that "elegance" means different things to the two
>>>>of us (eye of the beholder, again). The quality you describe
>>>>as "elegance" is something I'd prefer to call "clarity," and I
>>>>agree that it's a desirable attribute regardless of whether you
>>>>call it clarigance or eleganity.
>>>
>>> Interestingly enough, the actual, original definition of "elegant" is
>>> "minimalist". Which, in the context of the religion of CLC, ends up
>>> meaning exactly the opposite of "clarity" (since "clarity" usually ends up
>>> meaning "be as verbose as possible").
>>
>>It depends if you know C or not.
>>
>>One moron I had the displeasure of working with decided that something
>>like
>>
>>while(*d++=*s++);
>>
>>was not "clear" and needed to be expanded with long ariable names and to
>>use array notation and an exploded loop.
>>
>>I pointed out that any C programmer that didn't understand that code
>>had no right being in the team since its "bread ad butter" for any half
>>decent C programmer.
>
> I'd be willing to assert that for most working C programmers today, the
> above code is (pick all that apply): strange, cryptic, weird, "clever", not
> "clear", etc, etc, and that an explicit form with a loop would be much
> better in their eyes.
>
> Because, as is true of just about every population, most working C
> programmers today are idiots. It's what managememnt wants.

Its what people believe programmers should be. PC nonsense in the office
where QA and Doc resources are "empowered" to proof read code etc. The
world's gone mad.


--
"Avoid hyperbole at all costs, its the most destructive argument on
the planet" - Mark McIntyre in comp.lang.c
0 new messages