Re: Please don't do this (code fragment)

2002-01-15 Thread Thomas Bushnell, BSG
[EMAIL PROTECTED] writes:

 I don't find any such mention in KR [1978].  There is nothing I can
 see to guarantees that MAX_INT + 1  0.

KR [1978] is not the C standard.




Re: Please don't do this (code fragment)

2002-01-15 Thread elf
Good grief.  Can you be more constructive?  Do you have a reference
that supports the claim?

On Tue, Jan 15, 2002 at 12:11:35AM -0800, Thomas Bushnell, BSG wrote:
 [EMAIL PROTECTED] writes:
 
  I don't find any such mention in KR [1978].  There is nothing I can
  see to guarantees that MAX_INT + 1  0.
 
 KR [1978] is not the C standard.




Re: Please don't do this (code fragment)

2002-01-15 Thread Olaf Weber
Thomas Bushnell writes:

 Actually, the C standard does essentially guarantee two's complement
 arithmetic.  It specifies integer overflow behavior and
 signed/unsigned conversion behavior exactly.

It does for unsigned integers, but for signed integers overflow is
undefined behaviour.  The clearest statement of that is 3.4.3, albeit
in an example:

   3.4.3
 1 undefined behavior behavior, upon use of a nonportable or erroneous
   program construct or of erroneous data, for which this International
   Standard imposes no requirements
 2 NOTE Possible undefined behavior ranges from ignoring the situation
   completely with unpredictable results, to behaving during translation
   or program execution in a documented manner characteristic of the
   environment (with or without the issuance of a diagnostic message),
   to terminating a translation or execution (with the issuance of a
   diagnostic message). 
 3 EXAMPLE An example of undefined behavior is the behavior on integer
   overflow.

-- 
Olaf Weber

   (This space left blank for technical reasons.)




Re: Please don't do this (code fragment)

2002-01-14 Thread Samuel Tardieu
On 13/01, [EMAIL PROTECTED] wrote:

|   int i;
|   for (i = 0; i  -1; i += 1) {
| // ...
| if (terminal_condition)
|   break;  
| // ...
|   }
[...]
| Moreover, i is never used.  The loop could be reduced to
| 
|   while ((file = fts_read (dir)) != NULL) {
| // ...
|   }

Those are not equivalent: the first loop, while ugly, has a guard against
endless looping if fts_read always returns non-NULL for any reason (not
knowing what fts_read contains, it is hard to tell whether there is a
reason for this or not).

  Sam




Re: Please don't do this (code fragment)

2002-01-14 Thread Ian Eure
On Sunday 13 January 2002 10:01 pm, Samuel Tardieu wrote:
 On 13/01, [EMAIL PROTECTED] wrote:
 |   int i;
 |   for (i = 0; i  -1; i += 1) {
 | // ...
 | if (terminal_condition)
 |   break;
 | // ...
 |   }

 [...]

 | Moreover, i is never used.  The loop could be reduced to
 |
 |   while ((file = fts_read (dir)) != NULL) {
 | // ...
 |   }

 Those are not equivalent: the first loop, while ugly, has a guard against
 endless looping if fts_read always returns non-NULL for any reason (not
 knowing what fts_read contains, it is hard to tell whether there is a
 reason for this or not).

but it can still be reduced to a single while loop while retaining the same 
behavior as the original code:

while(file = fts_read(dir)) {
  // ...
}




Re: Please don't do this (code fragment)

2002-01-14 Thread elf
On Mon, Jan 14, 2002 at 07:01:17AM +0100, Samuel Tardieu wrote:
 On 13/01, [EMAIL PROTECTED] wrote:
 
 |   int i;
 |   for (i = 0; i  -1; i += 1) {
 | // ...
 | if (terminal_condition)
 |   break;
 | // ...
 |   }
 [...]
 | Moreover, i is never used.  The loop could be reduced to
 | 
 |   while ((file = fts_read (dir)) != NULL) {
 | // ...
 |   }
 
 Those are not equivalent: the first loop, while ugly, has a guard against
 endless looping if fts_read always returns non-NULL for any reason (not
 knowing what fts_read contains, it is hard to tell whether there is a
 reason for this or not).

A poor reason to write that code for several reasons.  

  1) It bounds the loop to the size of the integer /2 without
 explicitly indicating so. 
  2) If there is a problem, it silently hide the fact.
  3) It is non-deterministic.  Should the loop fail to terminate
 properly, the program will run for a relatively long time.  15
 seconds on the PIII 700MHz I'm using.

While I don't agree that this is an appropriate method for
guaranteeing termination, the same result with clearer expression
would be

  int loop_max = MAX_INT;
  while ((file = fts_read (dir)) != NULL  --loop_max) {
  }

I'd rather see the program fail to terminate so that I knew something
was awry instead of imposing an unforseen limitation on the program.
Moreover, the original depends on the fact that (MAX_INT + 1)  0
which, though true, is a guaranteed result.  Were I to be running a 64
bit CPU, the time to terminate either of these loops would approach
infinity (2^32*15s)-~2042 years.  I don't see the point of using such
a weak attempt to guarantee termination.

Cheers.





Re: Please don't do this (code fragment)

2002-01-14 Thread Craig Dickson
[EMAIL PROTECTED] wrote:

 On Mon, Jan 14, 2002 at 07:01:17AM +0100, Samuel Tardieu wrote:
  On 13/01, [EMAIL PROTECTED] wrote:
  
  |   int i;
  |   for (i = 0; i  -1; i += 1) {
  | // ...
  | if (terminal_condition)
  |   break;  
  | // ...
  |   }
  [...]
  | Moreover, i is never used.  The loop could be reduced to
  | 
  |   while ((file = fts_read (dir)) != NULL) {
  | // ...
  |   }
  
  Those are not equivalent: the first loop, while ugly, has a guard against
  endless looping if fts_read always returns non-NULL for any reason (not
  knowing what fts_read contains, it is hard to tell whether there is a
  reason for this or not).
 
 A poor reason to write that code for several reasons.  

Samuel wasn't defending the original code; he was just observing that
your suggested replacement was not functionally equivalent. Which it
wasn't.

   1) It bounds the loop to the size of the integer /2 without
  explicitly indicating so.

It's pretty clear if you understand how twos-complement arithmetic
works. Which is not to say it's the right thing to do, but I've seen
code that is much harder than this to understand.

   2) If there is a problem, it silently hide the fact.

It's impossible to know that based on the code fragment you posted.
There's no indication of what happens after the loop, or even most of
the inside of the loop. I'm sure you're familiar with the rest of the
code, but the rest of us probably aren't.

   3) It is non-deterministic.  Should the loop fail to terminate
  properly, the program will run for a relatively long time.  15
  seconds on the PIII 700MHz I'm using.

The original code is deterministic (the loop will definitely exit sooner
or later); your suggested replacement is not, unless it is guaranteed
that fts_read will eventually return NULL.

 While I don't agree that this is an appropriate method for
 guaranteeing termination, the same result with clearer expression
 would be
 
   int loop_max = MAX_INT;
   while ((file = fts_read (dir)) != NULL  --loop_max) {
   }

That's clearer, yes. It still sucks, unless there's a really good reason
to use MAX_INT as the limit. It's hard to say without knowing more about
the context of this tiny fragment of code, but I would guess that since
the loop condition is only used to guarantee eventual termination, the
limit could reasonably be set to a constant that is consistent across
platforms (whatever that constant might be -- 10^3, 10^6, 10^9,
whatever), rather than one that will vary by multiple orders of
magnitude depending on whether the target system uses 16-, 32-, or
64-bit ints.

 I'd rather see the program fail to terminate so that I knew something
 was awry instead of imposing an unforseen limitation on the program.

I'd rather see the program send a useful diagnostic message to stderr or
a log file, and either exit or properly recover from the error.

Craig


pgprIVUWj8rck.pgp
Description: PGP signature


Re: Please don't do this (code fragment)

2002-01-14 Thread elf
Reply-To: 
In-Reply-To: [EMAIL PROTECTED]

On Sun, Jan 13, 2002 at 10:49:09PM -0800, Craig Dickson wrote:
 [EMAIL PROTECTED] wrote:
 
  On Mon, Jan 14, 2002 at 07:01:17AM +0100, Samuel Tardieu wrote:
   On 13/01, [EMAIL PROTECTED] wrote:
   
   |   int i;
   |   for (i = 0; i  -1; i += 1) {
   | // ...
   | if (terminal_condition)
   |   break;
   | // ...
   |   }
   [...]
   | Moreover, i is never used.  The loop could be reduced to
   | 
   |   while ((file = fts_read (dir)) != NULL) {
   | // ...
   |   }
   
   Those are not equivalent: the first loop, while ugly, has a guard against
   endless looping if fts_read always returns non-NULL for any reason (not
   knowing what fts_read contains, it is hard to tell whether there is a
   reason for this or not).
  
  A poor reason to write that code for several reasons.  
 
 Samuel wasn't defending the original code; he was just observing that
 your suggested replacement was not functionally equivalent. Which it
 wasn't.

That is the crux of my argument.  In a 64 bit environment, this code
as written *is* equivalent to my rewrite.

1) It bounds the loop to the size of the integer /2 without
   explicitly indicating so.

 It's pretty clear if you understand how twos-complement arithmetic
 works. Which is not to say it's the right thing to do, 

Of course that is true.  Yet, such practices define poor style.  The
original author isn't writing what he means.  The fact that 2's
complement arithmetic wraps is a side-effect.  At least the use of
MAX_INT is an honest expression of the loop intent.

 but I've seen code that is much harder than this to understand.
 
And your point is what?  I'm saying nothing about the difficulty of
reading the code.  There is little point in having that discussion.

3) It is non-deterministic.  Should the loop fail to terminate
   properly, the program will run for a relatively long time.  15
   seconds on the PIII 700MHz I'm using.
 
 The original code is deterministic (the loop will definitely exit sooner
 or later); your suggested replacement is not, unless it is guaranteed
 that fts_read will eventually return NULL.

This is the kind of code that tends to break as systems evolve.  When
we moved from 16 bit to 32 bit, dependencies on machine organization
broke many programs that depended on them.  As I wrote in my reply, a
64 bit machine would have the same observable behavior as one without
the weak loop-termination guarantee.  Anything that requires more than
a month to terminate when one expects it to terminate in a few of
minutes has effectively hung.

  While I don't agree that this is an appropriate method for
  guaranteeing termination, the same result with clearer expression
  would be
  
int loop_max = MAX_INT;
while ((file = fts_read (dir)) != NULL  --loop_max) {
}
 
 That's clearer, yes. It still sucks, unless there's a really good reason
 to use MAX_INT as the limit. It's hard to say without knowing more about
 the context of this tiny fragment of code, but I would guess that since
 the loop condition is only used to guarantee eventual termination, the
 limit could reasonably be set to a constant that is consistent across
 platforms (whatever that constant might be -- 10^3, 10^6, 10^9,
 whatever), rather than one that will vary by multiple orders of
 magnitude depending on whether the target system uses 16-, 32-, or
 64-bit ints.

Still a poor choice.  You are hiding a limitation in the code that is
neither appropriate nor desirable.  Limiting the number of files, no
matter how you do it, will always change the semantics of the program.
Can you imaging people's suprise when the generate a search database
that appears to be missing a file that they know exists?  Setting a
time limit on the program run may be a more reliable standard; but
this, too, will be difficult to bound.  A process that runs without
bound will, at least, make itself known by loading the system.

 
  I'd rather see the program fail to terminate so that I knew something
  was awry instead of imposing an unforseen limitation on the program.
 
 I'd rather see the program send a useful diagnostic message to stderr or
 a log file, and either exit or properly recover from the error.

Of couse.  I agree that the code would be better if there was a
reasonable bound on the extent of the loop *AND* it reports that
something went awry.  But what should be the criteria?

The point is that the original code fragment fails to perform the
desired task deterministicly.  Within a few years, there will be a
significant number of machines running 64 bit CPUs.  Programs that use
this poor expression will be no better than those that don't.  I
believe this is the sort of failure-protection that Linus Torvalds
complains about.  Silently tolerating an error is worse than
discovering it when it executes without bound.

Cheers.




Re: Please don't do this (code fragment)

2002-01-14 Thread Torsten Landschoff
On Sun, Jan 13, 2002 at 10:23:51PM -0800, [EMAIL PROTECTED] wrote:
 Moreover, the original depends on the fact that (MAX_INT + 1)  0
 which, though true, is a guaranteed result.  Were I to be running a 64

... is not a guaranteed ...

I yet have to see a machine that does not use two's complement
for integer arithmetic.

cu
Torsten


pgpNT7VyvELTp.pgp
Description: PGP signature


Re: Please don't do this (code fragment)

2002-01-14 Thread Guus Sliepen
On Mon, Jan 14, 2002 at 12:04:44AM -0800, [EMAIL PROTECTED] wrote:

[How to write bad code]

Why don't you man fts_read and implement the correct way of checking
for errors?

-- 
Met vriendelijke groet / with kind regards,
  Guus Sliepen [EMAIL PROTECTED]


pgpuwz8FVAQoR.pgp
Description: PGP signature


Re: Please don't do this (code fragment)

2002-01-14 Thread David N. Welton

And what's more, it only indents two at a time.  Heretics!

-- 
David N. Welton
   Consulting: http://www.dedasys.com/
Free Software: http://people.debian.org/~davidw/
   Apache Tcl: http://tcl.apache.org/
 Personal: http://www.efn.org/~davidw/




Re: Please don't do this (code fragment)

2002-01-14 Thread Craig Dickson
Richard Kettlewell wrote:

 Even if you don't care about weird platforms, x  -1 is a
 ridiculously obscure test in this context; to achieve the same effect
 it would be much clearer to make x unsigned and do x =
 (unsigned)INT_MAX.

I find x = (unsigned) INT_MAX to be more obscure than the original.
When I first glanced at it, I thought, That's dumb, x is ALWAYS less
than or equal to INT_MAX by definition! Then my second thought was that
the cast on the constant will cause x to also be converted to unsigned.
In contrast, when I saw x  -1, I immediately realized it was testing
for wraparound.

To achieve almost the same effect (probably close enough in this
situation), it would be better to simply test for x  INT_MAX -- it's
clearer than either the original or your cast-dependent version, and
only stops one iteration sooner. Since in this case the actual number of
iterations was not the point (rather, merely that the loop should be
guaranteed to terminate eventually), it ought to be sufficient.

In any case, trying to find the best way to express a really bad idea is
futile.

Craig


pgpUi7TYwuAJK.pgp
Description: PGP signature


Re: Please don't do this (code fragment)

2002-01-14 Thread elf
On Mon, Jan 14, 2002 at 03:36:48PM +0100, Guus Sliepen wrote:
 On Mon, Jan 14, 2002 at 12:04:44AM -0800, [EMAIL PROTECTED] wrote:
 
 [How to write bad code]
 
 Why don't you man fts_read and implement the correct way of checking
 for errors?

I believe the author wrote the original loop because the fts_
functions could fail to operate as expected.

 
 -- 
 Met vriendelijke groet / with kind regards,
   Guus Sliepen [EMAIL PROTECTED]





Re: Please don't do this (code fragment)

2002-01-14 Thread Guus Sliepen
On Mon, Jan 14, 2002 at 08:58:57AM -0800, [EMAIL PROTECTED] wrote:

  Why don't you man fts_read and implement the correct way of checking
  for errors?
 
 I believe the author wrote the original loop because the fts_
 functions could fail to operate as expected.

Well please check if the author's assumptions are valid, and if so,
direct your attention to fixing fts_read(), everyone would benefit. The
discussion of how to make that ugly loop look nicer is useless.

-- 
Met vriendelijke groet / with kind regards,
  Guus Sliepen [EMAIL PROTECTED]


pgpU56pFzfY5Y.pgp
Description: PGP signature


Re: Please don't do this (code fragment)

2002-01-14 Thread Richard Kettlewell
Craig Dickson [EMAIL PROTECTED] writes:
 Richard Kettlewell wrote:

 Even if you don't care about weird platforms, x  -1 is a
 ridiculously obscure test in this context; to achieve the same
 effect it would be much clearer to make x unsigned and do x =
 (unsigned)INT_MAX.
 
 I find x = (unsigned) INT_MAX to be more obscure than the
 original.  When I first glanced at it, I thought, That's dumb, x is
 ALWAYS less than or equal to INT_MAX by definition!
 Then my second thought was that the cast on the constant will cause
 x to also be converted to unsigned.  In contrast, when I saw x 
 -1, I immediately realized it was testing for wraparound.

By 'make x unsigned' I mean 'declare as unsigned int x;'.

 To achieve almost the same effect (probably close enough in this
 situation), it would be better to simply test for x  INT_MAX -- it's
 clearer than either the original or your cast-dependent version, and
 only stops one iteration sooner. Since in this case the actual number of
 iterations was not the point (rather, merely that the loop should be
 guaranteed to terminate eventually), it ought to be sufficient.

If we're allowed to change the meaning, there are much more sensible
options still.  That wasn't really the point of my post.

-- 
http://www.greenend.org.uk/rjk/




Re: Please don't do this (code fragment)

2002-01-14 Thread Thomas Bushnell, BSG
Torsten Landschoff [EMAIL PROTECTED] writes:

 On Sun, Jan 13, 2002 at 10:23:51PM -0800, [EMAIL PROTECTED] wrote:
  Moreover, the original depends on the fact that (MAX_INT + 1)  0
  which, though true, is a guaranteed result.  Were I to be running a 64
 
 ... is not a guaranteed ...
 
 I yet have to see a machine that does not use two's complement
 for integer arithmetic.

Actually, the C standard does essentially guarantee two's complement
arithmetic.  It specifies integer overflow behavior and
signed/unsigned conversion behavior exactly.

So a machine can do its arithmetic some other way, but it has to make
it seem to the programmer that it's always two's complement.

Thomas




Re: Please don't do this (code fragment)

2002-01-14 Thread elf
On Mon, Jan 14, 2002 at 06:01:37PM +0100, Guus Sliepen wrote:
 On Mon, Jan 14, 2002 at 08:58:57AM -0800, [EMAIL PROTECTED] wrote:
 
   Why don't you man fts_read and implement the correct way of checking
   for errors?
  
  I believe the author wrote the original loop because the fts_
  functions could fail to operate as expected.
 
 Well please check if the author's assumptions are valid, and if so,
 direct your attention to fixing fts_read(), everyone would benefit. The
 discussion of how to make that ugly loop look nicer is useless.

I think you are missing the point.  As far as the program is
concerned, there is no valid reason to use the protecting loop to
guarantee termination.  I, too, agree that there is no reason to make
the loop nicer since there is no reason to write it in the first
place.

 
 -- 
 Met vriendelijke groet / with kind regards,
   Guus Sliepen [EMAIL PROTECTED]





Re: Please don't do this (code fragment)

2002-01-14 Thread Torsten Landschoff
On Mon, Jan 14, 2002 at 10:03:59AM -0800, Thomas Bushnell, BSG wrote:
  I yet have to see a machine that does not use two's complement
  for integer arithmetic.
 
 Actually, the C standard does essentially guarantee two's complement
 arithmetic.  It specifies integer overflow behavior and
 signed/unsigned conversion behavior exactly.

For real? Is that new with ISO C or was that in the original ANSI C
standard as well? Sorry, I gave away my ANSI C book a while before
and did not yet get it back :((

cu
Torsten


pgpWSabcVjFSJ.pgp
Description: PGP signature


Re: Please don't do this (code fragment)

2002-01-14 Thread Torsten Landschoff
On Mon, Jan 14, 2002 at 03:51:18PM +0100, David N. Welton wrote:
 
 And what's more, it only indents two at a time.  Heretics!

From standards.info:

   For the body of the function, our recommended style looks like this:

 if (x  foo (y, z))
   haha = bar[4] + 5;
 else

You want to discuss this on GNU lists? :)

cu
Torsten


pgpoS9kmwtUFv.pgp
Description: PGP signature


Re: Please don't do this (code fragment)

2002-01-14 Thread elf
I don't find any such mention in KR [1978].  There is nothing I can
see to guarantees that MAX_INT + 1  0.

On Tue, Jan 15, 2002 at 12:56:19AM +0100, Torsten Landschoff wrote:
 On Mon, Jan 14, 2002 at 10:03:59AM -0800, Thomas Bushnell, BSG wrote:
   I yet have to see a machine that does not use two's complement
   for integer arithmetic.
  
  Actually, the C standard does essentially guarantee two's complement
  arithmetic.  It specifies integer overflow behavior and
  signed/unsigned conversion behavior exactly.
 
 For real? Is that new with ISO C or was that in the original ANSI C
 standard as well? Sorry, I gave away my ANSI C book a while before
 and did not yet get it back :((
 
 cu
   Torsten