Using "break" to Break Out of Multiple Loops in One Call

  • Thread starter Thread starter O.B.
  • Start date Start date
O

O.B.

Does C# support anything like PHP's break command that optionally
accepts a parameter specifying how many loops to break out of?
 
No - 'break' and 'continue' always apply to the innermost loop.
You will need to set and test flags to do what you want (or - gasp - goto).
--
http://www.tangiblesoftwaresolutions.com
C++ to C#
C++ to VB
C++ to Java
Instant C#: VB to C#
Instant VB: C# to VB
Instant C++: VB or C# to C++/CLI
Java to VB & C# Converter: Java to VB or C#
 
Does C# support anything like PHP's break command that optionally
accepts a parameter specifying how many loops to break out of?

Not that Im aware of, and there would be grunts in the cleraing of
code if I found one...

for(;;int i(for(i=0;i<100;for(;console.writeline("{0}\n",i;for(;;i+
+for(;;break(2))))));
have to try that... someday... it sholdnt work, but giving an example
of why not.. it should stop at writing nothing but who knows...
//CY
 
O.B. said:
Does C# support anything like PHP's break command that optionally
accepts a parameter specifying how many loops to break out of?

No. And that's not very nice to begin with (requiring the programmer to
count carefully). Labeled breaks a la Java would be better, but it doesn't
have that either.

If you really think it makes the code easier to read, you can always use
goto. If the "multi-level break" is to handle a rare error condition, you
could throw an exception instead. If that's the case, though, you should
probably split things up in multiple functions. That would also allow you to
use "return" to break out of all loops in the current function.
 
I've always considered Java 'labelled breaks' as just a way for the Java
designers to get 'goto' into Java without admitting defeat. Especially when
you consider that you can use the labelled break to jump out of from any
braced block, not just loops.
--
http://www.tangiblesoftwaresolutions.com
C++ to C#
C++ to VB
C++ to Java
Instant C#: VB to C#
Instant VB: C# to VB
Instant C++: VB or C# to C++/CLI
Java to VB & C# Converter: Java to VB or C#
 
I've always considered Java 'labelled breaks' as just a way for the Java
designers to get 'goto' into Java without admitting defeat.

I agree with you, sort of.
Especially when
you consider that you can use the labelled break to jump out of from any
braced block, not just loops.

The main difference I see is that the syntax of the Java labeled break
reinforces the idea of a structured flow. It's true that you can add
braces to force an equivalence to a goto, but when you do so the language
is (if you're paying attention) giving you very loud clues about whether
or not that's an appropriate use of the "break-as-goto".

Personally, I'm not of the mind that "goto" statements are inherently
bad. They certainly can be misused, and may well be misused much more
than other language constructs. But they also have their place (and I
don't just mean as a replacement for falling through in "case" statements
:) ). I have found that, as I explore Java and implement real code using
it, that in a situation where I might have used a "goto", using a labeled
"break" provides similar functionality, but does so in a way that I think
makes the structure of the code clearer.

I prefer to believe that I never misuse a "goto" statement, but whether I
do or not, it's my belief that the Java syntax would make it a lot more
obvious to me if I'd abused the statement.

So, I'm not sure that in Java it was so much a matter of whether they were
admitting defeat or not, as it is a matter of trying to provide a slightly
different syntax to do the same thing, but in a more clear way that avoids
code maintenance issues that misuse of gotos can cause.

Granted, I don't know what the Java designers were actually thinking, but
I like to think that's at least part of why it's the way it is.

Of course, it begs the question: why isn't a similar syntax in C#? After
all, my after-the-fact impression of C#, having made the transition
backwards into Java from C#, is that C# seems to try to take what was best
of Java, while avoiding some of the more confusing, redundant, or
restrictive parts. Inasmuch as I personally find the labeled "break"
statements somewhat clearer than a "goto" statement, that doesn't exactly
fit into the impression I've formed.

But then, again, that's just my impression. I don't really know all of
the motivations behind the language design choices, and maybe they felt
they had a good reason to return back to the conventional "goto" statement.

Either way, I don't think there's anything inherently bad about labeled
"break" statements or "goto" statements. Sometimes they are just what you
need. Just remember not to aim at your foot when using them. :)

Pete
 
Either way, I don't think there's anything inherently bad about
labeled "break" statements or "goto" statements. Sometimes they are
just what you need. Just remember not to aim at your foot when using
them. :)

There's nothing bad in goto. I just love the longjmp() !!
 
There's nothing bad in goto. I just love the longjmp() !!

Well, sure. But these days we have exceptions to provide for that.

In fact, I'd say if anything, the descendant of longjmp() is much more
broadly accepted than that of goto. :)
 
Peter Duniho said:
Personally, I'm not of the mind that "goto" statements are inherently
bad. They certainly can be misused, and may well be misused much more
than other language constructs. But they also have their place (and I
don't just mean as a replacement for falling through in "case" statements
:) ).

Would you mind providing one such example?
 
Would you mind providing one such example?

Well, one common scenario is error-handling. In some cases, it makes
sense to have a single exit point in a method so that things can be
cleaned up in a single block of code rather than repeating that code, or
some subset, throughout the method. Using a "goto" statement allows you
to place that cleanup in a single place (I generally put it at the end of
the method), jumping to it on an error, and otherwise falling straight
through.

Nesting a bunch of "if()" statements can accomplish the same thing, but it
can create a difficult-to-read pattern of indentation. Using a "goto"
provides a lot of the same readability benefits that using exceptions for
failures can as well.

Are there other ways to do that? Sure, especially in C# (which has
"using" as well as exceptions). But those alternatives don't always
result in code that's as readable. And does the presence of those
alternatives mean that a "goto" statement is bad? No, not at all. Only
someone who had a blanket objection to using a "goto" statement for the
sake of the objection would say it was.

The fact is, even if you never write a "goto" statement, you use "goto"s
all the time. As long as you're keeping the code structured as you use a
"goto" statement, you haven't done anything the compiler wouldn't do
anyway. And if the use of the "goto" makes the code more readable, then
that's an advantage over shoe-horning your code into whatever alternative
the language would require to accomplish the same thing.

Pete
 
Peter Duniho said:
Well, one common scenario is error-handling. In some cases, it makes
sense to have a single exit point in a method so that things can be
cleaned up in a single block of code rather than repeating that code, or
some subset, throughout the method. Using a "goto" statement allows you
to place that cleanup in a single place (I generally put it at the end of
the method), jumping to it on an error, and otherwise falling straight
through.

Sounds like structured exception handling.
Are there other ways to do that? Sure, especially in C# (which has
"using" as well as exceptions). But those alternatives don't always
result in code that's as readable.

At the risk of repeating myself, would you mind providing one such example?
And does the presence of those alternatives mean that a "goto" statement
is bad? No, not at all. Only someone who had a blanket objection to
using a "goto" statement for the sake of the objection would say it was.

I've not stated nor implied that "goto" is "bad". I've only asked for an
example show where "goto" is favorable over these alternatives.
The fact is, even if you never write a "goto" statement, you use "goto"s
all the time. As long as you're keeping the code structured as you use a
"goto" statement, you haven't done anything the compiler wouldn't do
anyway.

Um, okay. What does that have to do with using "goto" in a higher level
language? The reason language designers give us constructs such as "if" and
"for" and "try...catch...finally" is to make code more readable. The fact
that it compiles to "jump" statements is irrelevant to this discussion.
And if the use of the "goto" makes the code more readable, then that's an
advantage over shoe-horning your code into whatever alternative the
language would require to accomplish the same thing.

I absolutely agree. Once again I ask, would you mind providing one such
example?
 
Sounds like structured exception handling.

It's not very different, no. However, the way the code is formatted and
the actual performance of the code is not the same, and thus one may be
desirable over the other, depending on specific wants and needs of the
programmer.
At the risk of repeating myself, would you mind providing one such
example?

I did. I'm sorry you are unable to conceptualize a piece of code that
shows how that would work. Since that's beyond your apparent ability to
grasp, here is a quick pseudo-code outline of what it would look like:

bool FDoSomething()
{
bool fRet = false;

// do something
if (something failed)
{
goto Failed;
}

// do something else
if (something else failed)
{
goto Failed;
}

// etc.

fRet = true;
Failed:
// cleanup (which may or may not use the success state to
// determine what to clean up)

return fRet;
}

There are other ways to represent the above, but a) they won't be as clear
and easy to read (one common alternative would be nested if()'s, which can
cause the indendation to get out of hand if there are many of them), and
b) one specific alternative would be to use exceptions to handle the
failure cases, but that's not at all desirable if the failure cases happen
with any sort of regularity, due to performance overhead.

Not that you should need any other examples, but a situation I ran into
recently was a series of conditional tests that involved some logic that
needed to be able to break out early when any condition tested true, but
continue testing more conditions otherwise. Normally, this would be
easily taken care of using if/else if/else logic. However, in this case
there were two issues that argued in favor of using "goto" statements:

1) In most cases, the affirmative action would have been empty for the
true case; the main goal was to eventually fall through to a common "we
met one of the conditions" section of the code. The final "if everything
failed" was a loop continue. Other than using gotos, the ways to
represent these would have been to have a series of empty true clauses for
the if() statements, or to reverse all the conditions, putting the loop
continue into each true clause rather than it being the final else clause.

2) In one of the if() statements, the code is more clear by breaking
the if() condition into two parts. But doing so breaks the chain of
if/else ifs.

By using "goto" statements for the affirmative cases, it allowed me to
write the code more simply as a sequence of individual if() statements,
where each condition represented exactly the higher-level design of the
code rather than the inverse, without using an exception with its overhead
to control program flow, and while still allowing me to break apart the
one if() in a way that made the intent of the code more clear.

Could the logic have been represented without using "goto" statements?
Absolutely. But it would not have been nearly as clear what the goal was,
or as efficient (had exception handling been used instead...frankly,
exception handling is a red herring as it deals with an entirely different
question).

The fact is, these situations don't come up a lot. But when they do, it's
nice to have that particular tool in the toolbox so that they can be
addressed in a more maintainable way.
[...]
The fact is, even if you never write a "goto" statement, you use
"goto"s all the time. As long as you're keeping the code structured as
you use a "goto" statement, you haven't done anything the compiler
wouldn't do anyway.

Um, okay. What does that have to do with using "goto" in a higher level
language? The reason language designers give us constructs such as "if"
and "for" and "try...catch...finally" is to make code more readable. The
fact that it compiles to "jump" statements is irrelevant to this
discussion.

Well, I disagree. The question of structured programming is relatively
independent of the language. I can write a structured program in
assembly, and I can (with some difficulty) write an unstructured program
in a language that is designed to make structured programming easier.

But if you're going to invoke the question of "the reason language
designers give us...", then it seems to be a direct conclusion that since
the C# language designers provided us the "goto" statement, it obviously
must be useful and appropriate in certain situations.
I absolutely agree. Once again I ask, would you mind providing one such
example?

I already did. But hopefully the elaboration above helps you understand
better.

Pete
 
I am not Peter Duniho but I can provide you an example from a real
world high-performance middle-ware product. I lifted this piece out
of the codebase of this product (http://www.zeroc.com)

Consider this snippet that listens on a socket:

public static void doListen(Socket socket, int backlog)
{
repeatListen:

try
{
socket.Listen(backlog);
}
catch(SocketException ex)
{
if(interrupted(ex))
{
goto repeatListen;
}

closeSocketNoThrow(socket);
throw new Ice.SocketException(ex);
}
}

public static bool interrupted(Win32Exception ex)
{
return ex.NativeErrorCode == WSAEINTR;
}

There are probably other ways to do this without using goto but you
will only end up obfuscating the intent of the code for some mythical
purity.
 
It's not very different, no. However, the way the code is formatted and
the actual performance of the code is not the same, and thus one may be
desirable over the other, depending on specific wants and needs of the
programmer.


I did. I'm sorry you are unable to conceptualize a piece of code that
shows how that would work. Since that's beyond your apparent ability to
grasp, here is a quick pseudo-code outline of what it would look like:

Actually, i was able to conceptualize the code - hence my remark that it
sounds like structured exception handling. You reinforced that you were
referring to exception handling when you mentioned "using" and "exceptions",
but you said that those alternatives ("using" and "exceptions") don't always
result in code that's as readable. I was hoping to see an example of that.
bool FDoSomething()
{
bool fRet = false;

// do something
if (something failed)
{
goto Failed;
}

// do something else
if (something else failed)
{
goto Failed;
}

// etc.

fRet = true;
Failed:
// cleanup (which may or may not use the success state to
// determine what to clean up)

return fRet;
}

There are other ways to represent the above, but a) they won't be as clear
and easy to read (one common alternative would be nested if()'s, which can
cause the indendation to get out of hand if there are many of them), and

Another way to handle that situation is to create another function from
which you "return" when a failure condition occurs. That's exactly what I've
done with one of our routines that processes millions of records from a flat
file. "Return" serves a similar purpose as "goto" - and has some of the same
"potential for abuse" arguements against it - but I personally still
consider it to be "more structured" than "goto" simply because the "label"
is well-defined.
b) one specific alternative would be to use exceptions to handle the
failure cases, but that's not at all desirable if the failure cases happen
with any sort of regularity, due to performance overhead.

I agree.
Not that you should need any other examples, but a situation I ran into
recently was a series of conditional tests that involved some logic that
needed to be able to break out early when any condition tested true, but
continue testing more conditions otherwise. Normally, this would be
easily taken care of using if/else if/else logic. However, in this case
there were two issues that argued in favor of using "goto" statements:
1) In most cases, the affirmative action would have been empty for the
true case; the main goal was to eventually fall through to a common "we
met one of the conditions" section of the code. The final "if everything
failed" was a loop continue. Other than using gotos, the ways to
represent these would have been to have a series of empty true clauses for
the if() statements, or to reverse all the conditions, putting the loop
continue into each true clause rather than it being the final else clause.
2) In one of the if() statements, the code is more clear by breaking
the if() condition into two parts. But doing so breaks the chain of
if/else ifs.
By using "goto" statements for the affirmative cases, it allowed me to
write the code more simply as a sequence of individual if() statements,
where each condition represented exactly the higher-level design of the
code rather than the inverse, without using an exception with its overhead
to control program flow, and while still allowing me to break apart the
one if() in a way that made the intent of the code more clear.

Actually, you could create a boolean function to test conditions and a
seperate method to implement the success/failure logic. That's what I
generally do:

void DoSomething()
{
if ShouldDoIt()
// Do affirmative action
else
// Do failure action
}

bool ShouldDoIt()
{
if (condition1)
return true;
else if (!condition2)
return false;
else if (condition3)
return true;

return true;
}

This has the notable advantage of following the rule that "each method
should do only one thing, and do it well". ShouldDotIt() is the decision
process, while DoSomething() is the work being done.
Could the logic have been represented without using "goto" statements?
Absolutely. But it would not have been nearly as clear what the goal was,
or as efficient (had exception handling been used instead...frankly,
exception handling is a red herring as it deals with an entirely different
question).

I agree that a "failure condition" is not the same as an "exception" and
that using exceptions in this situation is not desirable. However, there
*are* ways of coding that logic without exceptions that are even more
readable (IMO) than using "goto" (as I demostrated above).
[...]
The fact is, even if you never write a "goto" statement, you use "goto"s
all the time. As long as you're keeping the code structured as you use
a "goto" statement, you haven't done anything the compiler wouldn't do
anyway.

Um, okay. What does that have to do with using "goto" in a higher level
language? The reason language designers give us constructs such as "if"
and "for" and "try...catch...finally" is to make code more readable. The
fact that it compiles to "jump" statements is irrelevant to this
discussion.
Well, I disagree. The question of structured programming is relatively
independent of the language. I can write a structured program in
assembly, and I can (with some difficulty) write an unstructured program
in a language that is designed to make structured programming easier.

It's absolutely possible to write a structured program in assembly, I never
claimed that it wasn't. The C# compiler does a lot of things to make my life
easier. In fact, that's why I use a compiler instead of coding in assembly.
However, just because the C# compiler does something doesn't mean that I
should follow suit.
But if you're going to invoke the question of "the reason language
designers give us...", then it seems to be a direct conclusion that since
the C# language designers provided us the "goto" statement, it obviously
must be useful and appropriate in certain situations.

Presumably. I just haven't seen it yet.
I already did. But hopefully the elaboration above helps you understand
better.

No, it didn't. Thank you for providing some examples of where *you* think
"goto" statements are viable. I know that it wasn't your goal to convince
*me* that "goto" is viable in those situations, but it really is my goal to
find such a situation - which is why I asked if you would mind giving me an
example. It's not surprising that we don't agree, but I figured it was worth
asking. There was an outside chance that you would provide something I
hadn't seen before.

Happy coding.
 
Dilip said:
I am not Peter Duniho but I can provide you an example from a real
world high-performance middle-ware product. I lifted this piece out
of the codebase of this product (http://www.zeroc.com)

Consider this snippet that listens on a socket:

public static void doListen(Socket socket, int backlog)
{
repeatListen:

try
{
socket.Listen(backlog);
}
catch(SocketException ex)
{
if(interrupted(ex))
{
goto repeatListen;
}

closeSocketNoThrow(socket);
throw new Ice.SocketException(ex);
}
}

public static bool interrupted(Win32Exception ex)
{
return ex.NativeErrorCode == WSAEINTR;
}

There are probably other ways to do this without using goto but you
will only end up obfuscating the intent of the code for some mythical
purity.

Hmmm, here's my attempt, but you may be right. I'll admit that the original
is pretty good. Thanks for the example.

// The intent here should be pretty clear: keep calling
// "tryListen" until it returns "true". Although, it's not
// entirely clear *why* tryListen might return false.
public static void doListen(Socket socket, int backlog)
{
while (!tryListen(socket, backlog)) ;

// or

bool success = tryListen(socket, backlog);
while (!success)
success = tryListen(socket, backlog);
}

// The intent here may be a little obfuscated. It's not clear
// at all that you are going to retry if "interrupted".
public static bool tryListen(Socket socket, int backlog)
{
try
{
socket.Listen(backlog);
}
catch(SocketException ex)
{
if(interrupted(ex))
{
// Listen failed, try again.
return false;
}

closeSocketNoThrow(socket);
throw new Ice.SocketException(ex);
}

// Listen succeeded.
return true;
}

public static bool interrupted(Win32Exception ex)
{
return ex.NativeErrorCode == WSAEINTR;
}
 
[...]
Another way to handle that situation is to create another function from
which you "return" when a failure condition occurs.

Care to provide an example? :)

I don't really understand what you mean, actually. In the example I
provided, implicit is the understanding that the various potential points
of failures are dependent on each other, as is the data that has the state
for the function. I don't see how creating a new function to call would
help things.

How would you refactor the example I provided by adding new functions
"from which you 'return' when a failure condition occurs"? How would
doing so address the need to clean up the accumulated state of the
function at the end?
[...]
By using "goto" statements for the affirmative cases, it allowed me to
write the code more simply as a sequence of individual if() statements,
where each condition represented exactly the higher-level design of the
code rather than the inverse, without using an exception with its
overhead to control program flow, and while still allowing me to break
apart the one if() in a way that made the intent of the code more clear.

Actually, you could create a boolean function to test conditions and a
seperate method to implement the success/failure logic.

That's fine when it works. In the case to which I was referring, you'll
note that I wrote "in _most_ cases, the affirmative action would have been
empty".

In particular, one case needed to do some initialization. In addition,
the various conditions involved local variables specific to the loop being
executed. Passing all of that state into a helper function gets messy
IMHO, and the issue of initialization was a deal-breaker, as the example
is actually from something I was writing in Java, which doesn't have
pass-by-reference (which makes having the helper function do
initialization especially clumsy, on top of all the parameters that would
have had to be passed otherwise).

Finally, the suggestion of putting the sequence of tests into a separate
function does not actually address the one condition that was better
represented as a nested if() statement. Could I have compromised and put
that whole clause into a single if() statement? Sure. But why
compromise? Using a "goto" (okay, I admit...it was Java, and it was a
labeled "break") allowed the code to be concise, readable, and correct.

Frankly, the things you've suggested so far are IMHO exactly the example
of hoop-jumping that I think is pointless when all you're trying to do is
avoid using a "goto" statement. They are appropriate techniques where
warranted, but if avoiding a "goto" statement is the only motivation,
that's just busy work.
[...]
This has the notable advantage of following the rule that "each method
should do only one thing, and do it well". ShouldDotIt() is the decision
process, while DoSomething() is the work being done.

That rule isn't bad per se. But it's far too vague, and taken to the
extreme would imply that any method should only ever have a single
statement, and that you should never have conditional clauses in the same
method with statements that produce results. It is not in and of itself a
justification for avoiding a "goto" statement.

It's important to know when a rule either does not apply, or is overridden
by some other rule (such as not overcomplicating the code). Those pieces
of knowledge are every bit as important as knowing the rule in the first
place.

Pete
 
Dilip said:
I am not Peter Duniho but I can provide you an example from a real
world high-performance middle-ware product. I lifted this piece out
of the codebase of this product (http://www.zeroc.com)

Consider this snippet that listens on a socket:

public static void doListen(Socket socket, int backlog)
{
repeatListen:

try
{
socket.Listen(backlog);
}
catch(SocketException ex)
{
if(interrupted(ex))
{
goto repeatListen;
}

closeSocketNoThrow(socket);
throw new Ice.SocketException(ex);
}
}

public static bool interrupted(Win32Exception ex)
{
return ex.NativeErrorCode == WSAEINTR;
}

Hmm, I didn't know you could jump out of a try block with a goto, then re-enter
the block, very interesting...

How about:

public static void doListen(Socket socket, int backlog)
{
bool retry = true;
while (retry)
{
try
{
socket.Listen(backlog);
retry = false;
}
catch(SocketException ex)
{
if (!interrupted(ex))
{
closeSocketNoThrow(socket);
throw new Ice.SocketException(ex);
}
}
}
}
 
Peter Duniho said:
[...]
Another way to handle that situation is to create another function from
which you "return" when a failure condition occurs.

Care to provide an example? :)

No. This is a common Win32 technique. Google it.
Frankly, the things you've suggested so far are IMHO exactly the example
of hoop-jumping that I think is pointless when all you're trying to do is
avoid using a "goto" statement. They are appropriate techniques where
warranted, but if avoiding a "goto" statement is the only motivation,
that's just busy work.

There is no "hoop-jumping" in the examples I provided. I explained very
clearly the motivation for using them. If you want to see "hoop-jumping" to
avoid a "goto", see my response to Dilip's very short, efficient example of
a place where "goto" actually is warranted.
[...]
This has the notable advantage of following the rule that "each method
should do only one thing, and do it well". ShouldDotIt() is the decision
process, while DoSomething() is the work being done.

That rule isn't bad per se. But it's far too vague, and taken to the
extreme would imply that any method should only ever have a single
statement, and that you should never have conditional clauses in the same
method with statements that produce results.

Then don't take it to the extreme.
It is not in and of itself a justification for avoiding a "goto"
statement.

I didn't say that it was.
It's important to know when a rule either does not apply, or is overridden
by some other rule (such as not overcomplicating the code). Those pieces
of knowledge are every bit as important as knowing the rule in the first
place.

Obviously.
 
No. This is a common Win32 technique. Google it.

Are you serious?

I could have easily written the same thing when you asked me to elaborate
on my example, and been just as correct. I doubt you would have
considered that a reasonable reply.

You might want to look up "double standard". Your behavior at the moment
is unacceptable in polite society, to say the least.

As for your reply that "this is a common Win32 technique", I call
bullshit. You either have no clue what I meant in my original example, or
you have no clue what you yourself mean. Either way, there's no "common
Win32 technique" that addresses the issues I described. In fact, if
you're going to assert "common Win32 technique", the pattern I described
is a common enough example in DirectX code when initializing various
objects that are dependent on each other.
There is no "hoop-jumping" in the examples I provided.

You provided no examples. You specifically refused to. See above.

Honestly, I can't believe you had the nerve to reply as you did. I know
you like yanking my chain, but usually you manage to do it without acting
like a three-year-old. You've stooped pretty low today.

Pete
 
Another situation is where a particular operation will invalidate the
data being processes. For instance


start:
Generate dataset

for( - data set - )
while (something something)
for( - dataset - )
if (something something)
{
something that invalidates dataset
goto start:
}
 

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

Back
Top