[comp.lang.c] bug me now / bug me later

jharkins@sagpd1.UUCP (Jim Harkins) (06/08/90)

Lets say you have the following (you ADA people, please bear with me):

	#define SIZE	6
	#define STEP	2

Which is better:

	a.	for(i = SIZE; i != 0; i -= STEP)
or
	b.	for(i = SIZE; i > 0; i -= STEP)

Where this makes a difference is suppose SIZE is changed to 7.  Obviously
'a' goes into an infinite loop, while 'b' stops.  In the real world SIZE and
STEP could be variables that have been input by a user and manipulated a
gazillion times before being used in the for loop.

With method 'a' a bug is easy to spot, thus easy to fix.  But the bug may not
appear at a good time, the user may prefer that his system limp along rather
than hang completely.

With method 'b' the bug is harder to spot.  If you test your code well you
should catch these things, but a man named Murphy became famous anyway.  I
believe method 'b' is preferred by 'defensive programmers'.  It is also
possible that with method 'b' the loop body stomps over somebody elses
memory, with unknown but probably bad results.


So, how do you all feel about this?  As I'm writing for a military contract
I've cross-posted this to comp.lang.ada, I hope they don't get too upset.  And
please hurry, this came up for a reason :-)


-- 
jim		jharkins@sagpd1

I hate to see you go, but I love to see you walk away.

sampson@cod.NOSC.MIL (Charles H. Sampson) (06/08/90)

In article <811@sagpd1.UUCP> jharkins@sagpd1.UUCP (Jim Harkins) writes:
>
>Lets say you have the following (you ADA people, please bear with me):
>
>	#define SIZE	6
>	#define STEP	2
>
>Which is better:
>
>	a.	for(i = SIZE; i != 0; i -= STEP)
>or
>	b.	for(i = SIZE; i > 0; i -= STEP)
>
>Where this makes a difference is suppose SIZE is changed to 7.  Obviously
>'a' goes into an infinite loop, while 'b' stops.  In the real world SIZE and
>STEP could be variables that have been input by a user and manipulated a
>gazillion times before being used in the for loop.
>
     Neither is inherently better than the other; it depends on the problem.
If the problem requires that SIZE be a multiple of STEP, then a is preferable
because it reflects the problem requirement, but the requirement itself must
be validated at some point.  If there is no required relation between SIZE
and STEP, then b reflects that fact and is preferable.  (Of course, a is
wrong in the latter case, so b is strongly preferable.)

     All of this is MHO, naturally.

                               Charlie Sampson, CSC

P. S.  Anything written down here can be ignored.  The poster would not ac-
cept my followup because I had included more than I had written.  Strange,
I thought I had cut down the original article to the minimum needed to es-
tablish the context, then gave a compact response.  Apparently that's not
good enough.  The only solution in such a case seems to be to pad your
followup enough to get past that limitation.  Seems to me that the limita-
tion is self-defeating.  This is the end of my first try at padding.

boyne@hplvli.HP.COM (Art Boyne) (06/11/90)

jharkins@sagpd1.UUCP (Jim Harkins) writes:

>Lets say you have the following (you ADA people, please bear with me):
>
>	#define SIZE	6
>	#define STEP	2
>
>Which is better:
>
>	a.	for(i = SIZE; i != 0; i -= STEP)
>or
>	b.	for(i = SIZE; i > 0; i -= STEP)
>
>Where this makes a difference is suppose SIZE is changed to 7.
>'a' goes into an infinite loop, while 'b' stops.

Personally, I always use (b) for the simple reason that it WILL stop.
However, if the SIZE really is supposed to be a multiple of step,
I would consider the following preferable:

  if (SIZE % STEP != 0)
	assert("SIZE not multiple of STEP in function ...");
  for (i = SIZE; i > 0; i -= STEP)
    ...

This checks the assumption of exact multiples, and issues a diagnostic
if the assumption fails.  Of course, if SIZE and STEP are entered by
the user, the test should be done at the time of data entry, with a
simple error at that time, not at time of use.

Art Boyne, boyne@hplvla.hp.com

t-wader@microsoft.UUCP (Wade Richards) (06/12/90)

In article <811@sagpd1.UUCP> jharkins@sagpd1.UUCP (Jim Harkins) writes:
=}
=}Lets say you have the following (you ADA people, please bear with me):
=}
=}	#define SIZE	6
=}	#define STEP	2
=}
=}Which is better:
=}
=}	a.	for(i = SIZE; i != 0; i -= STEP)
=}or
=}	b.	for(i = SIZE; i > 0; i -= STEP)
=}

It depends on the situation. 

If you know that i will exactly equal zero (as in this case), then I think
that's what you should test for.  However, I would probally put:

assert( SIZE % STEP == 0 )

before the loop, to make sure nothing blows up, and (more importantly) to make
it quite clear what was at fault if it does blow up.


	--- Wade

firth@sei.cmu.edu (Robert Firth) (06/12/90)

In article <811@sagpd1.UUCP> jharkins@sagpd1.UUCP (Jim Harkins) writes:

>Which is better:
>
>	a.	for(i = SIZE; i != 0; i -= STEP)
>or
>	b.	for(i = SIZE; i > 0; i -= STEP)
>
>Where this makes a difference is suppose SIZE is changed to 7.  Obviously
>'a' goes into an infinite loop, while 'b' stops.  In the real world SIZE and
>STEP could be variables that have been input by a user and manipulated a
>gazillion times before being used in the for loop.

First, the coding of the loop should have nothing to do with the values
of SIZE and STEP.  The code you write should be determined by the
postcondition you wish to establish.  If the required postcondition
is "i=0" then the correct continuation test is "i/=0"; on the other
hand if the required postcondition is "i<=0" then the test is "i>0".
This would all be much clearer in a language that allowed the condition
to be written positively, thus:

	loop
	  ...
	  exit when i=0
	end loop

	-- postcondition: i=0

Secondly, the question of errors.  If the loop variable reaches a state
from which the postcondition is unreachable, there is an error in the
code.  For example, if the postcondition is "i=0", the recurrence
relation "i'<i" (ie the new value of i will be strictly less than the
old value), and the current value of i is negative, then the postcondition
will never be reached.  If you suspect this can happen, you should test
for the situation, *but this test should be separate from the loop
termination test and not merged with it*.  The reason is that, if the
test fails, the last thing you want to do is terminate the loop silently
with the postcondition false.  You probably want to raise an exception,
enter a recovery block, or take some similar emergency action.

Hope that helps.

brnstnd@kramden.acf.nyu.edu (06/14/90)

In article <7498@fy.sei.cmu.edu> firth@sei.cmu.edu (Robert Firth) writes:
> In article <811@sagpd1.UUCP> jharkins@sagpd1.UUCP (Jim Harkins) writes:
> >	a.	for(i = SIZE; i != 0; i -= STEP)
> >	b.	for(i = SIZE; i > 0; i -= STEP)
> First, the coding of the loop should have nothing to do with the values
> of SIZE and STEP.  The code you write should be determined by the
> postcondition you wish to establish.

Say what? Who cares what the value of i is after the loop? Most of the
time I want to see i uninitialized the moment the loop ends (though
there are enough exceptions to this rule that I don't want the language
to force it on me).

> Secondly, the question of errors.  If the loop variable reaches a state
> from which the postcondition is unreachable, there is an error in the
> code.

Again, who says there has to be a postcondition? The programmer is
thinking about the values i will take on trips through the loop, not
about the value it'll have afterwards.

---Dan

dolf@idca.tds.PHILIPS.nl (Dolf Grunbauer) (06/14/90)

In article <340021@hplvli.HP.COM> boyne@hplvli.HP.COM (Art Boyne) writes:
<jharkins@sagpd1.UUCP (Jim Harkins) writes:
<
<>Lets say you have the following (you ADA people, please bear with me):
<>
<>	#define SIZE	6
<>	#define STEP	2
<>
<>Which is better:
<>
<>	a.	for(i = SIZE; i != 0; i -= STEP)
<>or
<>	b.	for(i = SIZE; i > 0; i -= STEP)
<>
<>Where this makes a difference is suppose SIZE is changed to 7.
<>'a' goes into an infinite loop, while 'b' stops.
<
<I would consider the following preferable:
<
<  if (SIZE % STEP != 0)
<	assert("SIZE not multiple of STEP in function ...");
<  for (i = SIZE; i > 0; i -= STEP)
How about:

#if (SIZE % STEP) != 0
	SIZE not multiple of STEP
#endif

As now the compiler complains at compile time or your code will
run faster. The compiler gives the line number as the line will
probably not be valid C. I am aware that this trick will not work when
SIZE & STEP (or at least one of them) are variables rather than macro's.
-- 
Dolf Grunbauer      Tel: +31 55 433233 Internet dolf@idca.tds.philips.nl
Philips Information Systems            UUCP     ...!mcsun!philapd!dolf
Some kind of happiness is measured out in miles