Continuing an outer loop from an inner loop

D

dgiaimo

I was wondering what style of programming is preferred when continuing
an outer loop from within an inner loop. As far as I see it, there
are two possibilities, which I have given in pseudo-code below. The
first follows the strict, structural programming rule of only using
breaks and continues to control flow, while the second uses gotos.
Personally I prefer the second since it seems clearer, seems like it
would be easier to optimize, and doesn't use an artificial control
variable. What do you think?

void function(void)
{
int foundIt;

while(<condition1>)
{
foundIt = 0;

while(<condition2>)
{
if(<condition3>)
{
foundIt = 1;
break;
}
}
if(foundIt)
{
continue;
}
....
}
}

void function2(void)
while(<condition1>)
{
while(<condition2>)
{
if(<condition3>)
{
goto continueouter;
}
}
goto skipcontinue;
continueouter:
continue;
skipcontinue:
....
}
}
 
T

Tom St Denis

I was wondering what style of programming is preferred when continuing
an outer loop from within an inner loop.  As far as I see it, there
are two possibilities, which I have given in pseudo-code below.  The
first follows the strict, structural programming rule of only using
breaks and continues to control flow, while the second uses gotos.
Personally I prefer the second since it seems clearer, seems like it
would be easier to optimize, and doesn't use an artificial control
variable.  What do you think?

void function(void)
{
  int foundIt;

  while(<condition1>)
  {
    foundIt = 0;

    while(<condition2>)
    {
      if(<condition3>)
      {
        foundIt = 1;
        break;
      }
    }
    if(foundIt)
    {
      continue;
    }
...
  }

}

I wouldn't consider either a huge problem but I prefer the former to
the latter. But in the latter your gotos are all going in a forward
direction so it's ok. 'goto' only really becomes a problem if it's
overused [more so you have many labels] and/or you jump backwards in
the code.

I use goto for error cleanup for instance where they all are directed
to the tail end of the function to free up resources/etc. the nested
if e.g.

if (op() == OK) {
if (op() == OK) {
if (op() == OK) {
....

Is fucking ugly and I think should be destroyed on sight.

Tom
 
D

dgiaimo

I was wondering what style of programming is preferred when continuing
an outer loop from within an inner loop.  As far as I see it, there
are two possibilities, which I have given in pseudo-code below.  The
first follows the strict, structural programming rule of only using
breaks and continues to control flow, while the second uses gotos.
Personally I prefer the second since it seems clearer, seems like it
would be easier to optimize, and doesn't use an artificial control
variable.  What do you think?

void function(void)
{
  int foundIt;

  while(<condition1>)
  {
    foundIt = 0;

    while(<condition2>)
    {
      if(<condition3>)
      {
        foundIt = 1;
        break;
      }
    }
    if(foundIt)
    {
      continue;
    }
...
  }

}

void function2(void)
  while(<condition1>)
  {
    while(<condition2>)
    {
      if(<condition3>)
      {
        goto continueouter;
      }
    }
goto skipcontinue;
continueouter:
    continue;
skipcontinue:
...
  }

}

Actually, Now that I think about it, I guess there is a third option.
Not sure which I prefer now. This one does have one less goto, but,
then again, the label could be far from the goto if the while block is
long, so it might be hard to see where the goto goes to.

void function2(void)
while(<condition1>)
{
while(<condition2>)
{
if(<condition3>)
{
goto continueouter;
}
}
...
continueouter:
;
}
}
 
W

Willem

dgiaimo wrote:
) I was wondering what style of programming is preferred when continuing
) an outer loop from within an inner loop. As far as I see it, there
) are two possibilities, which I have given in pseudo-code below. The
) first follows the strict, structural programming rule of only using
) breaks and continues to control flow, while the second uses gotos.
) Personally I prefer the second since it seems clearer, seems like it
) would be easier to optimize, and doesn't use an artificial control
) variable. What do you think?
)
) void function(void)
) {
) int foundIt;
)
) while(<condition1>)
) {
) foundIt = 0;
)
) while(<condition2>)
) {
) if(<condition3>)
) {
) foundIt = 1;
) break;
) }
) }
) if(foundIt)
) {
) continue;
) }
) ...
) }
) }

I think you removed too much content because this could be rewritten to:

while(<condition1>)
{
int foundIt = 0;
while(!foundIt && <condition2>)
if(<condition3>)
foundIt = 1;
if (!foundIt) {
...
}
}

Which looks very natural.

) void function2(void)
) while(<condition1>)
) {
) while(<condition2>)
) {
) if(<condition3>)
) {
) goto continueouter;
) }
) }
) goto skipcontinue;
) continueouter:
) continue;
) skipcontinue:
) ...
) }
) }

Same here:

while(<condition1>) {
while(<condition2>)
if(<condition3)
goto skip:
...
skip:
}


But if you delegate the while(<condition2>) if(<condition3>) loop to a
function you get this:

while(<condition1>) {
if(look_for_condition3_in_condition2(...)) {
...
}
}

Which is a clear winner.

Details depend on the conditions, of course. Got a real-world example ?



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
 
D

Denis McMahon

Actually, Now that I think about it, I guess there is a third option.
Not sure which I prefer now. This one does have one less goto, but,
then again, the label could be far from the goto if the while block is
long, so it might be hard to see where the goto goes to.

That's what comments are for ...

/* jump to end of outer loop */ and
/* jump label from inner loop */

Rgds

Denis McMahon
 
D

dgiaimo

dgiaimo wrote:

) I was wondering what style of programming is preferred when continuing
) an outer loop from within an inner loop.  As far as I see it, there
) are two possibilities, which I have given in pseudo-code below.  The
) first follows the strict, structural programming rule of only using
) breaks and continues to control flow, while the second uses gotos.
) Personally I prefer the second since it seems clearer, seems like it
) would be easier to optimize, and doesn't use an artificial control
) variable.  What do you think?
)
) void function(void)
) {
)   int foundIt;
)
)   while(<condition1>)
)   {
)     foundIt = 0;
)
)     while(<condition2>)
)     {
)       if(<condition3>)
)       {
)         foundIt = 1;
)         break;
)       }
)     }
)     if(foundIt)
)     {
)       continue;
)     }
) ...
)   }
) }

I think you removed too much content because this could be rewritten to:

  while(<condition1>)
  {
    int foundIt = 0;
    while(!foundIt && <condition2>)
      if(<condition3>)
        foundIt = 1;
    if (!foundIt) {
      ...
    }
  }

Which looks very natural.

) void function2(void)
)   while(<condition1>)
)   {
)     while(<condition2>)
)     {
)       if(<condition3>)
)       {
)         goto continueouter;
)       }
)     }
) goto skipcontinue;
) continueouter:
)     continue;
) skipcontinue:
) ...
)   }
) }

Same here:

 while(<condition1>) {
   while(<condition2>)
     if(<condition3)
       goto skip:
   ...
   skip:
 }

But if you delegate the while(<condition2>) if(<condition3>) loop to a
function you get this:

  while(<condition1>) {
    if(look_for_condition3_in_condition2(...)) {
      ...
    }
  }

Which is a clear winner.

Details depend on the conditions, of course.  Got a real-world example ?

It would be difficult to post the actual example since it's kind of
involved. Basically, I'm trying to solve the "Strawberry Fields"
problem at:

http://www.itasoftware.com/careers/work-at-ita/hiring-puzzles.html

and part of my algorithm has a nested condition that needs to break
out of an outer loop. I'll probably be refactoring once I get the
algorithm to be sufficiently fast, so the problem may be moot.
However, considering that I may decide to send this in to them to try
to get hired, I do want this code to be reasonably stylistically
standard.
 
F

Felix Palmen

* Tom St Denis said:
I use goto for error cleanup for instance where they all are directed
to the tail end of the function to free up resources/etc. the nested
if e.g.

if (op() == OK) {
if (op() == OK) {
if (op() == OK) {
...

Is fucking ugly and I think should be destroyed on sight.

I second that. "Keep the code to the left" is a good policy and if a
goto can help with it (without causing any confusion, of course, so it
has to go forward, use clearly named labels, etc), it just adds to the
value of structural programming!

Regards,
Felix
 
A

August Karlstrom

I was wondering what style of programming is preferred when continuing
an outer loop from within an inner loop. As far as I see it, there
are two possibilities, which I have given in pseudo-code below. The
first follows the strict, structural programming rule of only using
breaks and continues to control flow, while the second uses gotos.
[...]

The most structured way is using neither break/continue nor goto:

void function(void)
{
while (condition1) {
while (condition2 && ! condition3) {
...
}
if (! condition3) {
...
}
}
}

It's much easier to reason about the correctness of a while loop if the
loop condition alone will determine when the loop is done.


/August
 
D

dgiaimo

On 2010-09-14 19:35, dgiaimo wrote:> I was wondering what style of programming is preferred when continuing
an outer loop from within an inner loop.  As far as I see it, there
are two possibilities, which I have given in pseudo-code below.  The
first follows the strict, structural programming rule of only using
breaks and continues to control flow, while the second uses gotos.

[...]

The most structured way is using neither break/continue nor goto:

void function(void)
{
        while (condition1) {
                while (condition2 && ! condition3) {
                        ...
                }
                if (! condition3) {
                        ...
                }
        }

}

It's much easier to reason about the correctness of a while loop if the
loop condition alone will determine when the loop is done.

/August

I think you mean:

void function(void)
{
while (condition1 && ! condition3) {
while (condition2 && ! condition3) {
...
}
if (! condition3) {
...
}
}
}

Right?
 
I

Ian Collins

I second that. "Keep the code to the left" is a good policy and if a
goto can help with it (without causing any confusion, of course, so it
has to go forward, use clearly named labels, etc), it just adds to the
value of structural programming!

The best way to keep the code to the left and keep the logic clear is to
move the inner loops out to their own functions. That way "return" is
all that's required to break out.
 
F

Felix Palmen

* Ian Collins said:
* Tom St Denis said:
I use goto for error cleanup for instance where they all are directed
to the tail end of the function to free up resources/etc. the nested
if e.g.
[...]

I second that. "Keep the code to the left" is a good policy and if a
goto can help with it (without causing any confusion, of course, so it
has to go forward, use clearly named labels, etc), it just adds to the
value of structural programming!

The best way to keep the code to the left and keep the logic clear is to
move the inner loops out to their own functions. That way "return" is
all that's required to break out.

Talking about loops, as soon as the inner code has a reasonable meaning
by itself, yes. But the example I quoted here (common cleanup code) is a
typical good usage of goto making the code even more readable.

Regards,
Felix
 
I

Ian Collins

* Ian Collins said:
* Tom St Denis<[email protected]>:
I use goto for error cleanup for instance where they all are directed
to the tail end of the function to free up resources/etc. the nested
if e.g. [...]

I second that. "Keep the code to the left" is a good policy and if a
goto can help with it (without causing any confusion, of course, so it
has to go forward, use clearly named labels, etc), it just adds to the
value of structural programming!

The best way to keep the code to the left and keep the logic clear is to
move the inner loops out to their own functions. That way "return" is
all that's required to break out.

Talking about loops, as soon as the inner code has a reasonable meaning
by itself, yes. But the example I quoted here (common cleanup code) is a
typical good usage of goto making the code even more readable.

There's never a good use for goto!
 
J

James Dow Allen

I think you mean:
  while (condition1 && ! condition3) {
    while (condition2 && ! condition3) {

I'm not going to try to figure out whether dgaimo or August
is correct here -- can you post a version with *goto* so it's
easier to see the logic :).

I *will* say this is NOT the first time c.l.c posters have
"improved" code by replacing goto with "structure" and ended up
*reversing* the test! Goto is much more straightforward:
you figure out where you want to go, and you (guess what?)
GO there.

Since goto is so easy for humans to grasp, one wonders if
the antidisestablishmentarians are concerned about automated
logic verifiers. Uhh, IMO by the time those are advanced
enough to be useful, they won't be confused by goto's.

c.l.c offers one-stop shopping for opinions about C style:

There's never a good use for goto!

Total nonsense. Convoluted loop conditions blur the meaning. break and
goto significantly simplify such constructs.
...
"Avoid hyperbole at all costs, its the most destructive argument on
the planet" - Mark McIntyre in comp.lang.c

Read a .sig line for a hint as to who is correct here. :)

However, considering that I may decide to send this in to them to try
to get hired, I do want this code to be reasonably stylistically
standard.

Then the question is easy to answer. Those who accept goto
tend not to be dogmatic and the silly
if (redundant_predicate) break;
won't bother them. The converse is NOT true: 'goto'
*might* very well be just the thing that blocks your hiring.

James Dow Allen
 
S

Shao Miller

Felix said:
Dogmatic "opinions" are just stupid.

'goto' can be enjoyable. Note how 'free(resource2)' might be
unreachable until 'USE_BAZ' is #defined as non-zero, but note the
consistency and legibility.

-----
#include <stdlib.h>
#include <stdio.h>

#define USE_BAZ 0

struct foo {
int x;
};

struct bar {
long x;
};

struct baz {
double x;
};

static const char *const test(void) {
const char *ret = "Failure.";
struct foo *resource1;
struct bar *resource2;
#if USE_BAZ
struct baz *resource3;
#endif

/**
* Resource allocation section.
**/
resource1 = malloc(sizeof resource1);
if (!resource1) {
fprintf(stderr, "'malloc' failed for 'resource1'.\n");
goto err_resource1;
}

resource2 = malloc(sizeof resource2);
if (!resource2) {
fprintf(stderr, "'malloc' failed for 'resource2'.\n");
goto err_resource2;
}

#if USE_BAZ
resource3 = malloc(sizeof resource3);
if (!resource3) {
fprintf(stderr, "'malloc' failed for 'resource3'.\n");
goto err_resource3;
}
#endif

/**
* Processing section.
**/
/* ... */
ret = "Success.";

/**
* Cleanup section.
**/
#if USE_BAZ
free(resource3);
err_resource3:
#endif

free(resource2);
err_resource2:

free(resource1);
err_resource1:

return ret;
}

int main(void) {
puts(test());
return 0;
}
 
W

Willem

dgiaimo wrote:
)> void function(void)
)> {
)> ? ? ? ? while (condition1) {
)> ? ? ? ? ? ? ? ? while (condition2 && ! condition3) {
)> ? ? ? ? ? ? ? ? ? ? ? ? ...
)> ? ? ? ? ? ? ? ? }
)> ? ? ? ? ? ? ? ? if (! condition3) {
)> ? ? ? ? ? ? ? ? ? ? ? ? ...
)> ? ? ? ? ? ? ? ? }
)> ? ? ? ? }
)>
)> }
)>
)> It's much easier to reason about the correctness of a while loop if the
)> loop condition alone will determine when the loop is done.
)
) I think you mean:
)
) void function(void)
) {
) while (condition1 && ! condition3) {
) while (condition2 && ! condition3) {
) ...
) }
) if (! condition3) {
) ...
) }
) }
) }
)
) Right?

Only if you miswrote your original code, which, as-is, repeated the outer
loop when condition3 was found, with a 'continue'. What you wrote here
breaks the outer loop instead.


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
 
S

Shao Miller

Shao said:
'goto' can be enjoyable. Note how 'free(resource2)' might be
unreachable until 'USE_BAZ' is #defined as non-zero, but note the
consistency and legibility.

... ... ...

Scratch the unreachable bit. That only counts if we leave resources
intact and:

return "Success.";

rather than:

ret = "Success.";

(Oops. Started the example one way then changed my mind during.)
 
M

Malcolm McLean

I was wondering what style of programming is preferred when continuing
an outer loop from within an inner loop.  As far as I see it, there
are two possibilities, which I have given in pseudo-code below.  The
first follows the strict, structural programming rule of only using
breaks and continues to control flow, while the second uses gotos.
Personally I prefer the second since it seems clearer, seems like it
would be easier to optimize, and doesn't use an artificial control
variable.  What do you think?

void function(void)
{
  int foundIt;

  while(<condition1>)
  {
    foundIt = 0;

    while(<condition2>)
    {
      if(<condition3>)
      {
        foundIt = 1;
        break;
      }
    }
    if(foundIt)
    {
      continue;
    }
...
  }

}

void function2(void)
  while(<condition1>)
  {
    while(<condition2>)
    {
      if(<condition3>)
      {
        goto continueouter;
      }
    }
goto skipcontinue;
continueouter:
    continue;
skipcontinue:
...
  }



}- Hide quoted text -

- Show quoted text -

I'd use

while(condition1)
{
while(condition2)
{
if(condition3)
break;
...
}
if(condition2)
continue;
...
}

Obviously condition2 needs to be a simple variable, not a call.
 
F

Felix Palmen

* Ian Collins said:
Well there may be one, but I've haven't found it in my 30 odd years of C
programming. I'll let you if I do find one.

The single best example, common cleanup code at the end of a function,
was already given in this thread. If during all your years of
programming, you just had Dijkstra's famous letter in your mind, it may
of course never have occured to you that a goto in such kind of code
would /improve/ the structure.

A lot of people tend to forget about the horrible ancient code that lead
to this goto-animosity in the first place.
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,049
Latest member
Allen00Reed

Latest Threads

Top