Velocity Reviews > Two-iteration loop

# Two-iteration loop

Christopher Benson-Manica
Guest
Posts: n/a

 11-10-2003
I have a situation something like this:

int foo;

for( foo=bar() ; foo <= bar()+1 ; foo++ ) {
if( !baz(foo) ) break;
/* do stuff with foo */
}

The idea is that the loop happens at most twice - once for foo=bar(), and once
for foo=bar()+1. If baz(foo) fails, I know I can stop. However, I don't
think this is the "elegant" way to get this behavior - there is a break (which
might be bad style, for some), and bar() may be called three times (which
doesn't seem optimal). I thought of

int foo=bar();

do {
if( !baz(foo) ) break;
/* doo stuff with foo */
} while( foo++ == bar() );

, but it's no better (and is somewhat more obfuscated, to boot). Any
thoughts?

--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.

Dave Vandervies
Guest
Posts: n/a

 11-10-2003
In article <boodf0\$sta\$(E-Mail Removed)>,
Christopher Benson-Manica <(E-Mail Removed)> wrote:
>I have a situation something like this:
>
>int foo;
>
>for( foo=bar() ; foo <= bar()+1 ; foo++ ) {
> if( !baz(foo) ) break;
> /* do stuff with foo */
>}
>
>The idea is that the loop happens at most twice - once for foo=bar(), and once
>for foo=bar()+1. If baz(foo) fails, I know I can stop. However, I don't
>think this is the "elegant" way to get this behavior - there is a break (which
>might be bad style, for some), and bar() may be called three times (which
>doesn't seem optimal). I thought of
>
>int foo=bar();
>
>do {
> if( !baz(foo) ) break;
> /* doo stuff with foo */
>} while( foo++ == bar() );
>
>, but it's no better (and is somewhat more obfuscated, to boot). Any
>thoughts?

How long is the chunk that "/*do stuff with foo*/" expands to?

If it's not too long, something like this might be a little bit cleaner
(for one thing, it makes it clear that it's a "do something again unless
baz() fails" and not a "loop until some condition is met"), though it's
not without its problems:
--------
foo=bar();
/*do stuff with foo*/
foo++;
if(baz(foo))
{
/*Note that this stuff is the same stuff we did above. If baz
returns nonzero we have to do it again.
*/
/*do stuff with foo*/
}
--------

Depending on how closely what you're doing with foo is tied to the rest
of the code there, it might be worth moving it to another function:
--------
foo=bar();
do_stuff_with(foo);
foo++;
if(baz(foo))
do_stuff_with(foo); /*again*/
--------

dave

--
Dave Vandervies http://www.velocityreviews.com/forums/(E-Mail Removed)
>You can quit emacs?

Yes, and after 12 weeks of rehab, you might even stay off the stuff.
--James Riden and Greg Andrews in the scary devil monastery

Ian Woods
Guest
Posts: n/a

 11-10-2003
Christopher Benson-Manica <(E-Mail Removed)> wrote in
news:boodf0\$sta\$(E-Mail Removed):

> I have a situation something like this:
>
> int foo;
>
> for( foo=bar() ; foo <= bar()+1 ; foo++ ) {
> if( !baz(foo) ) break;
> /* do stuff with foo */
> }
>
> The idea is that the loop happens at most twice - once for foo=bar(),
> and once for foo=bar()+1. If baz(foo) fails, I know I can stop.
> However, I don't think this is the "elegant" way to get this behavior
> - there is a break (which might be bad style, for some), and bar() may
> be called three times (which doesn't seem optimal). I thought of
>
> int foo=bar();
>
> do {
> if( !baz(foo) ) break;
> /* doo stuff with foo */
> } while( foo++ == bar() );
>
> , but it's no better (and is somewhat more obfuscated, to boot). Any
> thoughts?

If the value returned by bar() is loop invarient, assign it to a
variable. If bar() is an expensive (but invarient) computation this will
be a nice gain, and performing a single unnecessary check is at no cost.

You might do this:

int foo, startpos;

startpos=bar();
for (foo=startpos;foo<startpos+2 && !baz(foo);foo++) {
/* do stuff */
}

if you don't like the break. Personally, I don't mind "if (cond) break;"
especially at the beginning of loops.

If bar() isn't loop invarient and expensive, then you can still do it
nicely. something like:

int foo;
for (foo=0;foo<2;foo++) {

int barval=bar()+foo;
if (!baz(barval)) break;

/* do stuff */
}

If bar() isn't expensive and loop invarient, it doesn't really matter if
it's invoked a third.

Ian Woods

Ed Morton
Guest
Posts: n/a

 11-10-2003

On 11/10/2003 10:13 AM, Christopher Benson-Manica wrote:
> I have a situation something like this:
>
> int foo;
>
> for( foo=bar() ; foo <= bar()+1 ; foo++ ) {
> if( !baz(foo) ) break;
> /* do stuff with foo */
> }
>
> The idea is that the loop happens at most twice - once for foo=bar(), and once
> for foo=bar()+1. If baz(foo) fails, I know I can stop. However, I don't
> think this is the "elegant" way to get this behavior - there is a break (which
> might be bad style, for some), and bar() may be called three times (which
> doesn't seem optimal). I thought of
>
> int foo=bar();
>
> do {
> if( !baz(foo) ) break;
> /* doo stuff with foo */
> } while( foo++ == bar() );
>
> , but it's no better (and is somewhat more obfuscated, to boot). Any
> thoughts?
>

If the value returned from bar() never changes, then of course you'd assign that
to a variable outside of the loop:

int foo;
int fooMin = bar();
int fooMax = fooMin + 1;

for( foo=fooMin ; foo <= fooMax ; foo++ ) {
if( !baz(foo) ) break;
/* do stuff with foo */
}

Instead of breaking out of the loop if baz() fails, the obvious change would be
to only do the work if baz() succeeds, e.g.:

int foo;
int fooMin = bar();
int fooMax = fooMin + 1;

for( foo=fooMin ; foo <= fooMax ; foo++ ) {
if( baz(foo) ) {
/* do stuff with foo */
}
}

or even:

int foo;
int fooMin = bar();
int fooMax = fooMin + 1;

for( foo=fooMin ; (foo <= fooMax) && baz(foo) ; foo++ ) {
/* do stuff with foo */
}

If the condition becomes complex, write a macro:

#define ISVALID(foo) ((foo) <= fooMax ? baz((foo)) : 0)

int foo;
int fooMin = bar();
int fooMax = fooMin + 1;

for( foo=fooMin ; ISVALID(foo) ; foo++ ) {
/* do stuff with foo */
}

Now, if bar() doesn't always return the same value, we can easily modify the
above to:

#define ISVALID(foo) ((foo) <= bar() + 1 ? baz((foo)) : 0)

int foo;

for( foo=bar() ; ISVALID(foo) ; foo++ ) {
/* do stuff with foo */
}

Regards,

Ed.

Ben Pfaff
Guest
Posts: n/a

 11-10-2003
Christopher Benson-Manica <(E-Mail Removed)> writes:

> int foo;
>
> for( foo=bar() ; foo <= bar()+1 ; foo++ ) {
> if( !baz(foo) ) break;
> /* do stuff with foo */
> }
>
> The idea is that the loop happens at most twice - once for foo=bar(), and once
> for foo=bar()+1. If baz(foo) fails, I know I can stop. However, I don't
> think this is the "elegant" way to get this behavior - there is a break (which
> might be bad style, for some), and bar() may be called three times (which
> doesn't seem optimal).

If I understand the situation correctly, try this:

for (foo = bar(); baz(foo) && foo <= bar() + 1; foo++) {
/* do stuff with foo */
}
--
int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv wxyz.\
\n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\
);while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p[i]\
);}return 0;}