goto

S

Samee Zahur

In a recent thread, I saw the topic of goto coming up, so here's a
question:

With a background of asm langs, I know exactly why goto is to be
avoided. But does anyone know of a good way for "break"ing out of
nested loops? Say, breaking out by 2 levels out of the third nesting?
By "good way" I mean one without goto (like PHP has
"break 2;" or "continue 2;")

Samee
 
P

Phlip

Samee said:
In a recent thread, I saw the topic of goto coming up, so here's a
question:

The 2nd prior goto thread covered breaking out of nested loops.
With a background of asm langs, I know exactly why goto is to be
avoided. But does anyone know of a good way for "break"ing out of
nested loops? Say, breaking out by 2 levels out of the third nesting?

The best way is return. The second best way is goto.

Sometimes you can trip both loops to fail simultaneously. If that's elegant,
it might be the best way. Don't bend-over backwards to do it, and don't
duplicate 'if' statements. That's a maintenance hazard.

Good designs have short methods, so shortening methods might lead to good
design. So 'return' might become the best way.

The goal is not avoiding goto slavishly; the goal is good design.
By "good way" I mean one without goto (like PHP has
"break 2;" or "continue 2;")

That's a maintenance hazard. When you "refactor" code (look it up), you need
to be able to drag, drop, and test, assured that mistakes will cause instant
error messages, not silent bugs.

Accidentally moving 'continue 2' to a context where 2 is the wrong level
might create a silent bug.
 
R

Ravi Luthra

That is an interesting feature I didn't know PHP had.

I am just going to add an opinion to this, not necessarily the "Right
Way". I would suggest that generally nested loops are "for" loops, in
which case you typically know where your ending point is. In cases in
which you are looking for an item in a nested loop structure I would
say that perhaps you should have used an STL data structure. In other
situations that you are using a nested loop that needs to broken out of
twice, perhaps a little refactoring would be best, and instead of break
2; a nice return keyword would be suitable.

Wait forget about all that, throwing an exception and catching it after
the loop would be the perfect way to do this. (I am only kidding about
that.)
 
J

Jason

Samee Zahur wrote:
...does anyone know of a good way for "break"ing out of
nested loops? Say, breaking out by 2 levels out of the third nesting?
By "good way" I mean one without goto
<snip>

Isn't this one of the reasons why we have exceptions? You could wrap
the deeply nested code in a try/catch and then simply throw an
exception if you need to exit prematurely.

-Jason
 
R

REH

Jason said:
Samee Zahur wrote:

<snip>

Isn't this one of the reasons why we have exceptions? You could wrap
the deeply nested code in a try/catch and then simply throw an
exception if you need to exit prematurely.

-Jason

I consider that a very bad use of exceptions. I only use exceptions for
conditions I don't expect to occur in a correctly running program.

REH
 
I

Ioannis Vranos

Samee said:
In a recent thread, I saw the topic of goto coming up, so here's a
question:

With a background of asm langs, I know exactly why goto is to be
avoided. But does anyone know of a good way for "break"ing out of
nested loops? Say, breaking out by 2 levels out of the third nesting?
By "good way" I mean one without goto (like PHP has
"break 2;" or "continue 2;")



return_type res;

for(int i=0; i<width; ++i)
{
for(int j=0; j<height; ++j)
{
res= somefunc();

if(res== something)
break;

// ...
}


if(res== something)
break;

// ...
}



In some cases the above can be done like this:


return_type res= initial_value;

for(int i=0; i<width && res!= something; ++i)
{
// ...

for(int j=0; j<height && res!= something; ++j)
{
// ...

res= somefunc();
}

}
 
I

Ioannis Vranos

Ioannis said:
return_type res;

for(int i=0; i<width; ++i)
{
for(int j=0; j<height; ++j)
{
res= somefunc();

if(res== something)
break;

// ...
}


if(res== something)
break;

// ...
}



In some cases the above can be done like this:


return_type res= initial_value;

for(int i=0; i<width && res!= something; ++i)
{
// ...

for(int j=0; j<height && res!= something; ++j)
{
// ...

res= somefunc();
}

}


And of course, we can make res a static variable inside the loop:


for(int i=0; i<width; ++i)
{
static return_type res;

for(int j=0; j<height; ++j)
{
res= somefunc();

if(res== something)
break;

// ...
}


if(res== something)
break;

// ...
}
 
S

Samee Zahur

Phlip said:
The best way is return. The second best way is goto.
I think I agree, return is *the* best whenever *Possible*;
but like I said, when breaking out of 2 loops out of three, goto is
still the next best alternative, and this is one case where we
shouldn't be too fussy about avoiding this four-letter (key)word ;-)
Otherwise, we might have to introduce function barriers at rather
odd places - just for the sake of using return!
Good designs have short methods, so shortening methods might lead to good
design. So 'return' might become the best way.

Yes indeed, something to keep in mind BEFORE anyone designs loops
nested
THAT deep. Wise words indeed and well said.
Accidentally moving 'continue 2' to a context where 2 is the wrong level
might create a silent bug.

Hmm... here's something I missed, but doesn't that hold true for the
present breaks as well? I mean, it breaks out by only one level, but
cut-pasting it inside a deeper nest would often result in the same
silent
bug ... I don't think "break 2" kind of things would increase those
possiblities to anything more than they already are.


About Ravi's suggestion of using STL: yes, that almost always helps.
But in the real world we often find a nice programmer trying to write
nice codes (loops etc.) with data structures designed by someone not
*that* nice!

And, contrary to one of the suggestions, here's something I'd never
do: duplicated if's. As Philips has already pointed out, that poses
a SERIOUS maintenance hazard - for (albeit few)cases where return
statements are not possible, goto is apparently the way to go!

Although this is almost exclusively the place where goto still has
some good use, even such good uses are often loathed by bosses and
colleagues of an innocent programmer:(

That's why I was wondering if int breaks will ever be there in the
standard... so that this word would NEVER be needed EVER again! That
kind of stuffs should be faster to get into people's heads than a
*good* use of goto.

Samee

P.S. On a slightly different note of curiosity ... how are goto labels
scoped in C++? Function scoped I suppose? Is there a way of changing
the default scoping behavior of labels?
And (not that I'm planning to use it anywhere!) is there a short C++
equivalent for asm statements like "jmp [ebx]"? (I know things like
"call [ebx]" are done by function pointers)
"Pointers to labels" kind of things (I'm sure no one here has heard
of THAT:)? What wierd situations can possibly make this kind of
things actually useful?
(pls. avoid snappy answers like "none" ... I already know that on my
own:)
 
M

mschellens

This is a perfect example to use a goto.
This doublicated if is
a) ugly
b) slow
Like Phlip said:
"The goal is not avoiding goto slavishly; the goal is good design."

I think most people are sometime early on told 'avoid gotos' and
somehow internalize it.
This aversion probably comes from ancient BASIC times when people
whould have to jump forward and backward leading to messy 'spaghetti'
code.

Using goto when no other construct can be used is fine.
From my experience I would say: As long as you goto forward,
it is probably ok, but as soon as you have to goto backwards something
in your design is probably wrong (please post an example whoever
prooves
me wrong here).

And using exceptions for gotos is like exorcising the devil with the
beelzebub.

marc
 
K

Karl Heinz Buchegger

Samee said:
I think I agree, return is *the* best whenever *Possible*;

The point is: It is always possible.
Just refactor the code containing those 2 loops.
Move the nested loops into a function of their own and return
from there.

void foo()
{
// some code
for( int i = 0; i < some_number; ++i )
for( int j = 0; j < some_other_number; ++j )
if( j_equals_some_value )
goto loop_end;
}
}
j_equals_some_value:
// some more code
}

becomes:

void foo()
{
// some code
process_loops();
// some more code
}

void process_loops()
{
for( int i = 0; i < some_number; ++i )
for( int j = 0; j < some_other_number; ++j )
if( j_equals_some_value )
return;
}
 
M

mschellens

Well, of course it is always *possible* to avoid gotos,
but at which price?
Consider 10 other variables used in the loop, calculated before the
loop
and also neede after the loop. In this case your function would need 10
parameters...
And some of them might not even be needed in all cases and so on.
Use a goto in that case!

marc
 
K

Karl Heinz Buchegger

Well, of course it is always *possible* to avoid gotos,
but at which price?
Consider 10 other variables used in the loop, calculated before the
loop
and also neede after the loop. In this case your function would need 10
parameters...

In this case your code would need a redisign in any case :)
 
I

Ioannis Vranos

This is a perfect example to use a goto.
This doublicated if is
a) ugly
b) slow

Why?


Using goto when no other construct can be used is fine.


Yes. However in the mentioned cases you can do without goto.
 
M

m_schellens

a) please read Samee's post (number 3 in google groups)
b) the compiler has to check twice the same thing (and (probably) no
compiler
can optimize this away).
Yes. However in the mentioned cases you can do without goto.

You *can* always go without goto (please read my post number 5 for
further explanation)

marc
 
P

Phlip

m_schellens said:
a) please read Samee's post (number 3 in google groups)
b) the compiler has to check twice the same thing (and (probably) no
compiler
can optimize this away).

The programmer has to maintain the same thing twice, and (probably) no
project manager can optimize this away. ;-)
 
I

Ioannis Vranos

a) please read Samee's post (number 3 in google groups)
b) the compiler has to check twice the same thing (and (probably) no
compiler
can optimize this away).


If you have such efficiency concerns (there isn't any for regular application
development), you may use the suggestion that someone else provided, place the loop inside
a function (I think an inline would be better), and use return to exit all the nested loops.
 
S

Samee Zahur

Thank you all for the replies. So let me wrap it up. Basically,
the consensus we've reached here is this: many alternatives
exist, and there is no one best way to go for all cases, but
some are more suited to some situations than others. The
alternatives suggested were:

1) the code might need some refactoring
2) elegant ways might exist to trip both loops at once
3) try return statements
4) rethink datastructures to use STL algos
5) use goto
6) duplicated ifs :(
7) exceptions :((

Honestly, I'd NEVER use the last two options, although you might
prefer it. See the end of this post for explanations and logic.
And like I said before, Karl's solution is sometimes preferable
but I don't always... see (a) below for why.

If anyone can add to the list, I'm all ears, but this thread
seems to be going in circles now ... can we pls. move on?
In my last post, I posted a few new questions in the footnote -
no one seems to have noticed it, so let me quote it here:
That's why I was wondering if int breaks will ever be there in the
standard... so that this word would NEVER be needed EVER again! That
kind of stuffs should be faster to get into people's heads than a
*good* use of goto.


Samee


P.S. On a slightly different note of curiosity ... how are goto labels
scoped in C++? Function scoped I suppose? Is there a way of changing
the default scoping behavior of labels?
And (not that I'm planning to use it anywhere!) is there a short C++
equivalent for asm statements like "jmp [ebx]"? (I know things like
"call [ebx]" are done by function pointers)
"Pointers to labels" kind of things (I'm sure no one here has heard
of THAT:)? What wierd situations can possibly make this kind of
things actually useful?
(pls. avoid snappy answers like "none" ... I already know that on my
own:)

Any useful answers?



------------about some of the alternatives suggested----------
I know it's strange for the OP to post answers, but I felt like
some of the replies here needed explainations as to why they are
not always appropriate.
(a) Using returns: This is one of the best ways, but I'd go
against introducing functions just for the sake of being able
to use return. This code suggested here, e.g.
void foo()
{
// some code
process_loops();
// some more code



}


void process_loops()
{
for( int i = 0; i < some_number; ++i )
for( int j = 0; j < some_other_number; ++j )
if( j_equals_some_value )
return;


}
is fine if I can read foo() and understand what it does
without having to scroll up and down to process_loops all the
time. But in the cases that's not possible, such methods are
better avoided. Over-engineering is as big a problem to
maintenance/readability as is lack of modularity. We make
functions when (i) a block of code is in frequent use (ii)
we need to be able to plug blocks into codes at random, OR
(iii) a certain block of code represents a certain distict
concept or an entire action, introducing which improves
readability/maintenance.
(b) Using duplicated ifs: When rearranging codes, it is quite
easy (at least for me) to forget to change one of the if
statements and change just the other. Silent bugs creep up
easily this way. Besides, loops nested this deep are often
tight loops where every operation matters w.r.t. speed.
Checking if the control var was changed every time the middle
loop runs makes it slow - unnecessarily so.
(c) Using exceptions: NO-NO! throw exists to return control to
an outside scope, where current scope doesn't know enough to
handle the situation. When introducing a try block, compilers
have to ready the code for a throw command from *inside* any
of the functions/methods directly or indirectly called in the
try block. A throw command, on the other hand, in a function
(where there is no try) doesn't know the destination (corresponding
catch) of the control transfer. So compilers, when producing
binary code, cannot just substitute it for a goto statement -
they don't know which catch to go to! This means a throw
statement is more complicated than a simple goto statement
and may involve run-time overheads. Misusing exceptions like
this is SLOW!

If anyone opines against what I've said here, they may of course
explain their opinions, but I'd really like to see this discussion
moving forward, instead of just sticking to this argument over
which is better! I still have some confusions, as I said in the earlier
post, about C++'s treatment of labels w.r.t. scopes and stuff.

Samee
 
S

Samee Zahur

marc said:
it is probably ok, but as soon as you have to goto backwards something
in your design is probably wrong (please post an example whoever
prooves
me wrong here).

Hmm...dunno...is the direction of goto really that significant here?
"break 2;" kind of thing needs a forward jump, "continue 2;" usually
needs a backward jump. Both impair readability to the same extent,
right?

Samee
 
M

m_schellens

even for continue you have to goto to the END of the loop.
Otherwise the secont part of the for(1st;2nd;3rd) would not be checked
and the
third part of the for would not be executed.
marc
 

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,755
Messages
2,569,534
Members
45,007
Latest member
obedient dusk

Latest Threads

Top