[net.lang.c] Breaking out of several nested loops

tischler@ihuxs.UUCP (Mark D. Tischler) (10/02/84)

A while ago, someone told me that they
thought it was possible to break out of
several nested loops at once using a
statement like "break 3".  It would,
for example, break out of the following
sequence:

	i = 1;
	while
	   .
	   .
	   for
	      .
	      .
	      switch
		 .
		 .
		 break;
	i = 2;

It doesn't seem to work, and I was wondering
if perhaps someone knew of a way to do
that without having to set 3 separate
boolean flags?  Please send mail to
me.  Thanks.
-- 

				Mark Tischler
				(312) 420-7272 (home)
				(312) 979-2626 (work)
				ihnp4!ihuxs!tischler

td@alice.UUCP (Tom Duff) (10/03/84)

The correct way to break out of multiply nested control constructs (using the
example in the referenced article) without using 3 separate boolean flags is:

	i=1;
	while(...){
		...
		for(...;...;...){
			...
			switch(...){
				...
				goto Out;
			}
		}
	}
Out:	i=2;

buls@ssc-vax.UUCP (Rick Buls) (10/04/84)

>> The correct way to break out of multiply nested control constructs (using the
>> example in the referenced article) without using 3 separate boolean flags is:
>> 
>> 	i=1;
>> 	while(...){
>> 		...
>> 		for(...;...;...){
>> 			...
>> 			switch(...){
>> 				...
>> 				goto Out;
>> 			}
>> 		}
>> 	}
>> Out:	i=2;
>> 
>> 

	Very UNstructured!!!!!!!!!!

	Try the following:
   	i=1;
	struct(????);
	i=2;
	...
struct(????)
	...
{
	...
   	while(...){
   		...
   		for(...;...;...){
   			...
   			switch(...){
   				...
   				return;
   			}
   		}
   	}
}
   


   where ???? is what ever parameters are needed!!!!

dan@digi-g.UUCP (Dan Messinger) (10/04/84)

If possible, you could make that section of code a seperate function,
and use 'return' from any point in the nested loops to effectively break
out.  The number of parameters that would be needed to be passed to this
routine could make this unacceptable, in which case you could use the
dreaded 'goto'.

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (10/06/84)

Hurray for Tom Duff, too!

It's amazing how programmers resort to great contortions to avoid
a simple, clean forward goto to break out of nested loops.

hansen@pegasus.UUCP (10/08/84)

One of the proposals that was supposed to be brought up before the last
committee meeting was a way to make breaking out of deeply nested loops
structured such that the following:

>> 	i=1;
>> 	while(...){
>> 		...
>> 		for(...;...;...){
>> 			...
>> 			switch(...){
>> 				...
>> 				goto Out;
>> 			}
>> 		}
>> 	}
>> Out:	i=2;
>> 

would become:

>> 	i=1;
--  whileloop:
>> 	while(...){
>> 		...
>> 		for(...;...;...){
>> 			...
>> 			switch(...){
>> 				...
-- 				break whileloop;
>> 			}
>> 		}
>> 	}
>>	i=2;
>> 

The idea is to be able to label while, for and do-while loops and be able to
use those labels on break and continue statements. This provides for a very
structured and much more readable and maintainable coding style, in my
opinion, than the equivalent code using goto's or separate procedures. This
feature is commonly called a "break n" capability in the literature and
other languages.

What does everyone think? Is this a worthy attempt at making the language
more structured and orthogonal? Send in your votes!

					Tony Hansen
					pegasus!hansen

padpowell@wateng.UUCP (PAD Powell) (10/09/84)

I love the idea of labelled loops.

Just make sure that you support "break <label>;" and "continue <label>".

Just to make life really simple, PROHIBIT multiple labels with the same
name in a procedure body.  Should cause no problems, should make
LINT a joy to use, as you would not get "warning: label redefinition..."
messages.

Patrick Powell

ignatz@wlcrjs.UUCP (David M. Ihnat) (10/09/84)

<I'll never submit to putting in that silly lineater sop in my messaes...>

(Despite the fact that the latest version of news encourages me to
reship the entire text of the reference message, I can't see doing so.
If you're stepping into this conversation this late, uh...go back and
catch up.)

Re the comment on the suggestion to use a 'goto' to get out of deeply
nested structures:

> 	Very UNstructured!!!!!!!!!!

Sorry--STRUCTURED CODE IS NOT RELIGION.  If trying for structured code
produces more complicated, un-understandable code than the so-called 
'unstructured' code, then it's getting in the way of the job.  Please,
please remember:  Nothing is forbidden.  Gotos CAN be avoided in all
cases; but it remains a fact that there are times when a simple,
single exit point out of a deeply nested structure will be far clearer
and simpler than a convoluted approach intended to appease  the ghods
of structured programming.  (FYI, I *am* a proponent of structured
programming techniques; the approach I'm postulating, fortunately, was
explained to me by aprofessor long gone but not forgotten.)

	Dave Ihnat
	Analysts International Corporation
	ihnp4!wlcrjs!ignatz
	ihnp4!aicchi!ignatz
	ihnp4!wlcrjs!aicchi!ignatz
-- 
				Dave Ihnat
				Analysts International Corporation
				aicchi!ignatz or wlcrjs!ignatz
				(w) 882-4673  (h) 784-4544

td@alice.UUCP (Tom Duff) (10/10/84)

It's hard to imagine how this proposal (break with a label argument breaks
out of the labelled statement) could be considered `more structured' than
a goto.  It's nothing more than a goto that goes to the statement after
the one with the label.  Of course, the next thing you'll want is to
do the same thing to continue.  That could make continue the semantic
equivalent of goto.  The only restriction would be that you could only
use these things from within the labelled statement.

This is the sort of proposal that closet spaghetti-chefs pull out because
they haven't got the talent or perverted mindset (or whatever it takes)
to write their code without gotos.  They hope that by changing the name
and mumbling nonsense about reducible flow-graphs
they can get the structured-programming fascists to give them back 99%
of their gotos.

Neither side of the goto argument should be satified with this sort of thing.
Those in favor of gotos should not hide their lamp under a bushel, but
should expose it to all of us, if not in pride then as fair warning.
Those opposed should denounce the proposal as invidious subversion.

To quote Ken Thompson:  `if you want go get somewhere, GOTO is the
way to do it.'  If you're going to write code that jumps all over the place,
have the grace not to whitewash it.

crm@duke.UUCP (Charlie Martin) (10/10/84)

I may be dense, but I simply cannot see what makes
 label: while ( cond )
	{
	...
	if ( break cond )
		break label ;

	}

any more 

structured'' than
	while( cond )
	{
	...
	if ( break cond )
		goto end ;
	}
end :	;

In addition, the construct above has the advantage that it
looks like it is doing what it is really doing -- that is, the


break label'' version says that it is breaking a loop labellled


label'', which label is at the beginning, but it is effectively
GOING to the END.

Don Knuth wrote an article that was pretty good on Structured
Programming With GOTO's that covered all off this sort of
thing, by the way -- I can dig up a formal reference if needed.

Charlie Martin
(...mcnc!duke!crm)

rogerh@arizona.UUCP (Roger Hayes) (10/10/84)

Tony Hansens' proposal was to allow labels on loops, like
	foo: while (x)
	{
		...
		.{.
			break foo;
		.}.
	}

I like the idea of named loops.  This syntax is very bad (sorry, Mr. 
Hansen).  Is foo a legal label?  Can one say "goto foo"?  Is this fragment
legal?  (If so, what does it mean?)

baz: 	i += j;
	break baz;

I am not pleased with any of the alternatives I have thought of for syntax.
The problem is to give a name to the loop body, without creating an ambiguity
with any other legal construct, and hopefully by using something that will
seem familiar to present C users.  It would be nice to avoid making another 
keyword.

I have thought of, and rejected:
	while (x) foo: { ... } foo	
	while (x) loop foo { ... } foo
	while (x) foo:: { ... } foo

I like the first best, but it does create two kinds of labels (on regular 
statements and on compound statements) with the same syntax, but different
semantics.  I put trailing labels (which must match the name of the loop)
on all of them, because I want a marker to see where the break will jump
to, without counting levels of braces.

	Roger Hayes
	University of Arizona
	Dept. of Computer Science

PS: I am strongly in favor of more-than-6-character-names in the C standard.
In addition to all the reasons advanced so far, the C language is tied pretty
closly to UN*X, and UN*X is headed towards flexnames.  Let the inconvenience 
be on the past (6-chars) not on the future.

radford@calgary.UUCP (Radford Neal) (10/10/84)

I think labelling loops and allowing one to break out of several by
using that label is NOT a good idea for the ANSI standard. 

What does this really get you? Nothing as far as I can see. Breaking 
out of nested loops with a goto is not at all obscure. The only advantage
of a multi-level exit from a structured programming point of view is
that it guarantees that only forward branches are made, presumably
increasing readability. The proposal manages to avoid this advantage,
however, by using the same syntax for a label used as the object of a
goto as for a label used in a break. If I came across a label at the beginning
of a while loop, my first impression would be that someone RESTARTS the
loop by jumping there.

If you really want to do such things, the best construct is the "situation
case" proposed by C. T. Zahn. This works like this:

      notice-situation <situation1>, <situation2>, ...
         ...
         <code, including statements like "situation-occurs <situation>">
         ...
      case <situation1>: <code>
      case <situation2>: <code>
      ...
      end

(This isn't a proposal for a C-oriented syntax.) 

In the block of code at the beginning, statements can occur indicating
that a particular situation has occured (possibly in deeply nested 
contexts). After this block are a number of (optional) sections of code
that get jumped to when the corresponding situations arise. After that
section of code is done, the statement following all this gets done.

This gets you multi-level exits and more as well, in a potentially more
understandable form.

REALLY though, none of this is neccessary. I find that single level exits
are quite convenient 95% of the time, and gotos work fine for the rest.
I really thought this was all settled five years ago during the great
structured programming debate. Using a goto statement once every few
thousand lines of code is perfectly reasonable.

Furthermore, this is just the sort of thing which should NOT go in a
standard, as it would render all existing compiler non-standards-conforming
for no good reason, reducing the probability that the standard will
be taken seriously. Anybody who went out and wrote lots of code using the
new construct thinking it was portable because it was "standard" would
be fooling themselves.

      Radford Neal
      Dept. of Computer Science
      University of Calgary

jim@randvax.UUCP (Jim Gillogly) (10/11/84)

--------------
Breaking out of a nested loop with a "break label" instead of a GOTO is
supposed to be much better for program verification.  Rather than being an
arbitrary control transfer, it merely exits from a well-defined
environment.  At least that's what Bill Wulf told us when he invented it
for BLISS.

The only time I use GOTO's in C is to get out of these loops, and I write
a whole lot of C.

I heartily concur with David Dyer-Bennett's assertion that "break label"
is much better than "break n", having used and tried to debug with both
in BLISS.  I would add an outer loop now and then and forget that there
was an "exitloop 3" on the next screen.

For stand-alone completeness, we're talking about leaving nested loops as
follows:

     label:
	for (i = 0; i < n; i++)
	{       ...
		for (j = 0; j < m; j++)
		{       ...
			if (error)
				break label;
		}
	}

Jim Gillogly            {vortex, decvax}!randvax!jim

quiroz@rochester.UUCP (Cesar Quiroz) (10/11/84)

> Tony Hansens' proposal was to allow labels on loops, like
> 	foo: while (x)
> 	{
> 		...
> 		.{.
> 			break foo;
> 		.}.
> 	}
> 
> I like the idea of named loops.  This syntax is very bad (sorry, Mr. 
> Hansen).  Is foo a legal label?  Can one say "goto foo"?  Is this fragment
> legal?  (If so, what does it mean?)
> 
> baz: 	i += j;
> 	break baz;
> 

I think the proposed syntax is not that bad.  First of all, it doesn't 
introduce a new usage in C, labels are already valid where proposed.
Now, the idea requires a simple extension to the semantics of the language,
namely: That 'break <label>' works only for breakable statements! This,
of course, means two things: 

1._ That <label> refers to a 'breakable' statement,
2._ That the break occurs inside the range of that statement.

You can add a field to the 'label' entries in your symbol table (say
'breakable').  You set this flag appropriately as soon as you recognize what
type of statement your label is adorning. (Minor difficulties can arise
if you allow <label> [<label> ..] <statement>, because you have to fix not
just one label, but this shouldn't be a concern here). Then, if you see

	break foo;     (as per the example)

you can determine that the usage is valid. On the other hand, 'break baz;' 
is nonsense, can be easily shown to be that, and can be handled properly
(it 'breaks' your whole program :-)). It  should go without saying, but
the compiler shouldn't scream "syntax error", because 'break <label>' would
be a syntactically valid construction, but an error message like
"cannot break from ..." or "unbreakable ..." (but not "stainless ..." :-))
Additional remarks concerning the competence of the perpetrator are usually
considered unnecessary or in bad taste.

There is also the (unrelated?) proposal of adding the same label at the
end of a compound statement.  Sound as it is, retrofitting it into a 
language seems too painful in terms of the expected benefits.


Cesar Augusto  Quiroz Gonzalez

Department of Computer Science     {allegra|seismo}!rochester!quiroz
University of Rochester            or
Rochester,  NY 14627               quiroz@ROCHESTER

dat@hpcnoe.UUCP (dat) (10/11/84)

	I have to agree.

	One of the biggest problems in the realm of professional
programmers (hows THAT for a concept!) (scary) is that they don't 
understand that there CAN BE EXCEPTIONS TO EVERY RULE.

	Sure it is good to try to avoid goto's like the plague, but
in some cases it IS the best possible approach.  

	My last job was with a DoD contractor and we had in writing
that we COULD NOT USE ANY GOTO's.  PERIOD.  NO EXCEPTIONS.  And we
were using Fortran VII so there weren't a whole lot of alternatives
in some cases.

	I just foisted the code that I felt necessitated the 'goto' to
someone else and bypassed the whole issue)

	What the hell - Assembler and 'Spaghetti Code' are interesting,
and a CHALLENGE to debug (especially if it ain't commented and it ain't
yours!) right?  We're getting too wimpy.  :-)

	Structuredly,
				Dave Taylor
				Colorado Networks

rcd@opus.UUCP (Dick Dunn) (10/11/84)

> >> The correct way to break out of multiply nested control constructs (using the
> >> example in the referenced article) without using 3 separate boolean flags is:
>...
> >> 	while(...){
>...
> >> 				goto Out;
> 
> 	Very UNstructured!!!!!!!!!!
> 
> 	Try the following:

...and the parent article suggests ripping this nest out into a separate
procedure which has, as parameters, all of the variables needed in the nest
of control constructs--this allows replacing the "goto" with a "return". 
I guess the trailing-line-eater bug got the parent article, 'cause there
wasn't a ":-)" at the end.

I'm sure glad to see that someone would violate all concepts of modularity
(yanking part of the innards out of a procedure), clean interface (defining
a new procedure without regard to how many parameters might be needed),
and, dare I say the word, efficiency.  No, really, I AM glad about that,
because the more "programmers" there are who bow to the sacred "structured"
idol and who stupidly believe "structured"=="no goto's", the longer I will
be able to be paid an absurdly high salary for being able to produce real
software (though it's sometimes painful to do maintenance on code written
by a "structured code" dogmatist).
-- 
Dick Dunn	{hao,ucbvax,allegra}!nbires!rcd		(303)444-5710 x3086
   ...Relax...don't worry...have a homebrew.

rcd@opus.UUCP (Dick Dunn) (10/11/84)

Bad confusion on the multi-level break issue:

> One of the proposals that was supposed to be brought up before the last
> committee meeting was a way to make breaking out of deeply nested loops
> structured such that the following:
>  [illustration of multi-level-break problem]
> would become:
> --  whileloop:
>...
> -- 				break whileloop;
>...
> The idea is to be able to label while, for and do-while loops and be able to
> use those labels on break and continue statements. This provides for a very
> structured and much more readable and maintainable coding style, in my
> opinion, than the equivalent code using goto's or separate procedures...
>...
> What does everyone think? Is this a worthy attempt at making the language
> more structured and orthogonal? Send in your votes!

The idea for such a language construct is reasonable, but it should not be
muddled into the standardization process.  Standards committees working on
existing languages are NOT in the role of designing, or even revamping, a
language.  Naturally, they will have to make some changes--but only for
those situations where there is a very real problem in the existing form(s)
of the language.

In fact, the proposed construct does not answer any particular crying need.
Multi-level breaks are comparatively uncommon.  They certainly aren't so
common and so much of a problem as to justify a CHANGE to the language.

Finally, the proposed solution has a very interesting characteristic:

	Without the extension, the multi-level break has two parts--a
	transfer and a label.

	With the extension, the multi-level break has two parts--a transfer
	and a label.

The notable difference is that with the extension, the label is at a
different point (possibly by quite a distance) than the point to which
control is actually transferred.  I'm hard-pressed to see that as an
advantage.
-- 
Dick Dunn	{hao,ucbvax,allegra}!nbires!rcd		(303)444-5710 x3086
   ...Relax...don't worry...have a homebrew.

quiroz@rochester.UUCP (Cesar Quiroz) (10/12/84)

Minimal editing done in quotes below!_ 
<From a posting by  Charlie Martin  (...mcnc!duke!crm)>

> I may be dense, but I simply cannot see what makes
> 	...
> 		break label ;
> 
> any more  structured'' than
> 	...
> 		goto end ;
> 	...
> end :	;
> 

I, for one, will not say that one of the constructs is more
''structured'' that the other. Nor I couldn't care less. For
the 'structured'/'unstructured' debate usually moves real fast
into religious beliefs.

What makes me decide for the 'break' style over the 'goto' style
is a set of other considerations.  To start with,  you may agree
(so I hope) that the few goto's that are really harmless (or 
unavoidable) are the ones that take you out from a loop/procedure
or some other flow of control commitment into safe code again. Like
the one above, which is probably less dangerous than adding flags
to check how to get out. (My typing errors increase exponentially 
with the number of declarations).

However, if those are really the only goto's we really want, why bother
implementing the whole power of an all purpose 'goto'? To take your own
words on this matter:

> In addition, the construct above has the advantage that it
> looks like it is doing what it is really doing -- that is, the
> break label'' version says that it is breaking a loop labellled
> label'', which label is at the beginning, but it is effectively
> GOING to the END.
> 

Yes, 'break' (or 'exit' or whatever reason may suggest) says what
it is doing. And it can do only what it says, no more no less. In
addition, 'break' is NOT going to the end. It's going beyond :-)

> Don Knuth wrote an article that was pretty good on Structured
> Programming With GOTO's that covered all off this sort of
> thing, by the way -- I can dig up a formal reference if needed.
> 

Amen brother. Every side seems to have a Holy Book. (And yes, the 
article is really good -- my copy appears in Raymond Yeh's collection
"Current Trends in Programming Methodology", Vol.1, Prentice Hall (1977),
but there is a footnote that says that the copyright is by ACM (1974)). But
again, best arguments don't use religion.


Cesar Augusto  Quiroz Gonzalez {allegra|seismo}!rochester!quiroz

ron@brl-tgr.ARPA (Ron Natalie <ron>) (10/12/84)

The major advantage of not introducing a new construct which is
redundant to the old goto construct is that you'll still have to
keep the goto around (it really is part of the language) and why
complicate the language with yet another unstructured construct.

-Ron

crm@duke.UUCP (Charlie Martin) (10/12/84)

The problem with getting into a religious discussion is that
everyone seems to think that you have a religious opinion...

Let me make another attempt to make my argument clear -- I claim that
while it is indeed true that ANY algorithm can be expressed in
proper structured-programming-without-goto's (proven by Boehm &
Jacopini), there are things which one often wants to do which are
best expressed in current programming languages (modulo efficiency
constraints) by doing them with a goto.  The example that we have
been discussing is one of those.

The solutions that are available are: use a branching statement to
bust out of the loop; have a language construct which magically
hides a branching contruct busting out of the loop; or put a new
boolean test into each outer loop, so that processing terminates
when that is set.

The third solution is the one that can be inferred from the original
proof.  It has some advantages for proof-of-correctness.

The second method is the one that is used by the break (and continue)
statements, and is the one that I feel is correct.  It limits the scope
of the goto, and doesn't tempt people into indiscetions as often.
However, these statements as they exist won't cover certain cases:
for example, a simple break won't take you out of nested loops; a
more difficult example is something like this:
	
	/* code for user input */
	while ( not complete )
	do
	   retry:
	   /* transfer to this point for retry of whole thing */

		while( not right)
		do
		   get input a, b, c
		   if ABORT-INPUT received
			goto retry 
		   fi
		od

	od 
	/* end example */.

In both of these cases, WHILE IT IS PROVABLY POSSIBLE TO WRITE A
GOTO-LESS PROGRAM TO DO THEM, the solution with goto's has advantages
in speed and amount of generated code-and-data.

The best solution is something that eliminates goto's or limits their
ability to muck up control flow, but that provides for all those odd
situations which these exemplify.  A label-continue/label-break sentax
might do that effectively (say by defining the label as an optional part
of the beginning and/or ending of a loop) but I want to feel convinced
that it is going to be able to do everything I would use a goto for
(which isn't damnall much, I admit -- I've only written one goto in C
ever.)  (And wouldn't have ever written one in Pascal at all, were it
not for the absense of a loop break.)

My only complaints about the labelled-loop/break-label solution are
these:
	1) it's a goto anyway -- why fuss about it?  In particular,
	   why claim it is more ``structured'' than the same control-
	   flow with the horrible word ``goto'' in the code?

	2) The notation suggested is itself counter-intuitive --
	   you are G*T*-ing to a label, but the label is up at
	   the top and you are going to the bottom (!?)

	3) do these solutions *really* cover everything?  Are you
	   going to leave setjmp/longjmp in the language?  They
	   can be transformed out too, you know...

Charlie Martin
(...mcnc!duke!crm)

hansen@pegasus.UUCP (Tony L. Hansen) (10/13/84)

This following is a formal proposal for an addition to the ANSI Standard C
language. This is a modification of an August draft of the standards document.

						Tony Hansen
						pegasus!hansen
----
Subject: labels

Currently labels are allowed within the language only as targets of goto
statements. I would like to propose that they be allowed in two additional
places as well: as arguments to the break and continue statements.

Consider the code fragment

	while (...) {
	    weekloop:
		while (...) {
			...
			switch (...) {
				...
				case ...:
					...
					goto endloop;
				...
					goto endloop2;
				...
			}
		...
		endloop: ;
		}
		endloop2:
		...
	}

Where does the "goto endloop" logically take us?  What it is actually doing
is continuing the second while loop (labeled weekloop).  Is it obvious from
the code?  I think that when looking at that code and seeing the goto, I
would look for the label, possibly scanning the entire function for it.
Finally I would find the label within the same loop as the switch statement.
I would then see the closing brace following the label and search back for
the matching opening brace. Finally I would see that it is a pair of braces
from a while loop and going to that place will do the same thing as a
continue of that loop.

Similarly, where does the "goto endloop2" logically take us? What it is
actually doing is breaking out of the second while loop. Is that obvious
from the code? I feel that the same mental juggling around would have to be
done to figure out what the real affect of the goto is.

Instead, I would like to propose the following code fragment:

	while (...) {
		weekloop:
		    while (...) {
			...
			switch (...) {
				...
				case ...:
					...
					continue weekloop;
				...
					break weekloop;
				...
			}
		...
		}
		...
	}

Here I have used the logically extended continue and break statements to
accept a label argument. Think through the mental juggling that now has to
be done to realize what happens when the continue statement is reached:
"Hmmm, weekloop has to have been defined above. ... There it is. And it's
being continued. That's simple enough to follow." Similarly for the new
break statement. I can tell almost at a glance which loop is being continued
or broken out of rather than doing all sorts of mental juggling to figure 
out what the goto is really doing.

I propose that section 6.5 be rewritten along the following lines:

    6.5 Jump statements

    The jump statements (goto, continue, break, and return) cause an
    unconditional jump to another place.

    6.5.1 Labeled statements

    Syntax
	    identifier : statement

    Constraints

	Any statement may be preceded by a label prefix that serves to declare
    the identifier as a label. The only use of a label is as a target of a
    goto, continue or break statement. The labels are in a separate name space
    from other identifiers.

    6.5.2 goto statements

    Syntax
	    goto identifier ;

    Semantics
	Control may jump unconditionally by means of the goto statement. The
    identifier must be a label located anywhere in the current function.

    6.5.3

    Syntax
	    continue identifier   ;
			       opt

    Constraints
	A continue statement may appear only in a loop body. The optional
    identifier must be a label prefixing a while, for or do iteration
    statement enclosing the continue statement.

    Semantics
	A continue statement causes a jump to the loop-continuation portion of
    the enclosing iteration statement; that is, to the end of the loop. If no
    label is specified, the smallest enclosing iteration statement is used;
    otherwise the labeled enclosing iteration statement is used. More
    precisely, in each of the statements

      loop:		      loop:		      loop:
	while (...) {		do {			for (...) {
	  ...			  ...		 	 ...
	  continue;		  continue;	  	continue;
	  ...			  ...		  	...
	  continue loop;	  continue loop;  	continue loop;
	  ...			  ...		  	...
	contin: ;		contin: ;		contin: ;
	}			} while (...);		}

    unless the continue shown without a label reference is in an enclosed
    iteration statement (in which case it is interpreted within that
    statement), it is equivalent to "goto contin;". (Following the contin: is
    a null statement.) Irregardless of other enclosing iteration statements,
    the "continue loop" statement is equivalent to "goto contin;".

    6.5.4 The break statement

    Syntax
	    break identifier   ;
			    opt

    Constraints
	A break statement may appear only in a switch body or loop body. The
    optional identifier must be a label prefixing a switch statement, or a
    while, for or do iteration statement, enclosing the break statement.

    Semantics
	A break statement without a label identifier terminates execution of
    the smallest enclosing switch or iteration statement. A break statement
    with a label identifier terminates execution of the enclosing switch or
    iteration statement which is prefixed with the named identifier. More
    precisely, in each of the statements

      loop:		      loop:		      loop:
	while (...) {		do {			for (...) {
	  ...			  ...		 	 ...
	  break;		  break;	  	break;
	  ...			  ...		  	...
	  break loop;	  	break loop;  		break loop;
	  ...			  ...		  	...
	}			} while (...);		}
      contin:		      contin:		      contin:
	...			...			...

    unless the break shown without a label reference is in an enclosed switch
    or iteration statement (in which case it is interpreted within that
    statement), it is equivalent to "goto contin;". Irregardless of other
    enclosing switch or iteration statements, the "break loop" statement is
    equivalent to "goto contin;".

    6.5.5 The return statement
    ....

geoff@desint.UUCP (Geoff Kuenning) (10/13/84)

I think some people in the pro-break camp are missing some of the pro-goto's
point.  Suppose you are reading this code:

	label1:	for (i = 0;  i < n;  i++) {
		    while (x ()) {
			...
			if (condition)
			    break label1; *or* goto label2;
		    }
		}
	label2:

Assume we have a fairly large program here;  perhaps the outer loop won't
actually fit on a 24-line screen (give me an Ann Arbor, please!).

Now, when you come to the "break" statement, and you want to follow the code
flow, what do you do?  Obviously, you search (upwards) for label1.  Then you
have to fight Bell-style curly-brace conventions to locate the end of the
loop, which is where the next statement executed will actually be found.  What
a pain!

With the unrestricted goto, of course, you have no idea which direction to
search in, so the problem is even worse.  But if, like most modern programmers,
the author used goto's *only* to break out of nested loops, you can count on
a forward search.  And when you find the matching label, you are done!

The disadvantage of unrestricted goto's is not so much program validation as
optimization (quick:  you are compiling the statement at "label2".  What's in
the registers?  What if there's a backwards jump in the code below?).  This
was the reason Dijkstra originally criticized goto's (and, by the way, he
*did* explicitly state that completely goto-less programs were superior--the
title of his 1968 letter to CACM was "Goto's Considered Harmful").

I think that we need a restricted form of the goto (like the break <label>),
but in a syntax that places the target at the next statement executed.  This
would allow compiler writers to do good global optimizations.  One solution
might be to leave the language syntax alone, but add a compiler switch that
says, in effect, that all goto's are of the restricted "break" form, and it
can safely make this assumption when optimizing.  Even better, we could make
that be the default, and require the switch when compiling programs that had
unrestricted goto's.  The advantage of this is that we could call the switch
"-bozo" :-).

-- 
	Geoff Kuenning
	First Systems Corporation
	...!ihnp4!trwrb!desint!geoff

henry@utzoo.UUCP (Henry Spencer) (10/14/84)

> ... if those are really the only goto's we really want, why bother
> implementing the whole power of an all purpose 'goto'? ...

Because the all-purpose goto, revolting though it is, already exists in
C and does not need re-inventing.

Personally, I think "return" makes a dandy multi-level exit; I haven't
used, or missed, goto for years.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

henry@utzoo.UUCP (Henry Spencer) (10/14/84)

> ...and the parent article suggests ripping this nest out into a separate
> procedure which has, as parameters, all of the variables needed in the nest
> of control constructs--this allows replacing the "goto" with a "return". 
> I guess the trailing-line-eater bug got the parent article, 'cause there
> wasn't a ":-)" at the end.
> 
> I'm sure glad to see that someone would violate all concepts of modularity
> (yanking part of the innards out of a procedure), clean interface (defining
> a new procedure without regard to how many parameters might be needed),
> and, dare I say the word, efficiency.  ...

Gee, I've always found that modularity and clean interface were *improved*
by breaking the innards out into a separate function any time they start
getting non-trivial.  As an accidental side effect of this, "return" then
suffices for multi-level exits.  And it's never produced any efficiency
problems in my stuff.  Efficiency is the standard excuse for ugliness,
and that's usually all it is:  an excuse.

Note that I am not suggesting that you can retrofit this approach into
existing code without rethinking said code to make it clean and modular.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

honey@down.FUN (10/14/84)

to make program verification easier, i hereby renounce the use of
goto's forever.  please send a program verifier to the above address.
	peter honeyman

jec@iuvax.UUCP (10/15/84)

[just in case]

	I don't think the labelling of loops is all that necessary for the
"break"ing out of loops, but it would be nice to have it for the
"continue"ing of loops.  As long as it is being used for continuing why not
allow it and keep goto for those that like to do it the other way. 


--


					James Conley
					Indiana University
					68K Education Board Project
					...{isrnix|iuvax}!jec

bright@dataio.UUCP (Emperor) (10/15/84)

Since breaking out of several nested loops is unstructured anyway,
isn't using an unstructured goto the most appropriate thing to do?
I've seen some pretty unreadable 'structured' code caused by attempts
to avoid using gotos, when a rewrite of the code using a goto simplified
it tremendously.
					Walter Bright

gino@voder.UUCP (Gino Bloch) (10/15/84)

[this is a broken loop]

Well, I have an opinion too.  I imagine trying to find WHERE the break or goto
takes me to.  Assume that I have a listing or an editor without the `%' command.
I think it's easier to guess what happens with this:
	while (...)
	    {
		{
		    {
			{
			...
			goto bkpt;
			}
		    }
	    bkpt: ...
		}
	    }


than it will be with this:
	while (...)
	    {
		someloop: while (...)
		{
		    {
			{
			...
			break someloop;
			}
		    }
		}
	    }

Except, of course, in simple cases that aren't very deeply nested - but those
cases are easy anyway.
-- 
Gene E. Bloch (...!nsc!voder!gino)

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (10/16/84)

Gee, I thought everyone knew that the most general structured loop is
	startloop
		...
		on condition (...) leaveloop
		...
	repeatloop
which can mimic a "while" or "do .. while" loop if one or the other
of the body sections is null.  The rules for "structuredness" seem
to be: a loop invariant is being maintained (and is stated EXPLICITLY,
perhaps in a comment), the loop is entered at the top, and there is
only one exit from the loop.  C's "break" and "continue" violate this
just as much as a "goto" would.  But so what; a conscientious
program designer will "think structured" no matter what language he
is using.  I have yet to see an automated tool (including ADA) for
enforcing proper programming practice that can compensate for ignorance
or stupidity on the part of its user.

lwall@sdcrdcf.UUCP (Larry Wall) (10/16/84)

In article <468@voder.UUCP> gino@voder.UUCP (Gino Bloch) writes:
>Well, I have an opinion too.  I imagine trying to find WHERE the break or
>goto takes me to...

So do I, and so do I...

Hypothetical examples of named breaks never ring quite true, because they
neglect the fact that most loops have a semantic value.  I think this point
has been neglected by the pro-namers.  Named loops (and blocks) are useful
*abstractions*, and it's always nice to be able to name your abstractions.

Arguments about whether your abstraction should be named at the beginning
or the end miss the point.  If a loop is to be labeled, it should be labeled
at both ends.  I can just see it: the Los Angeles City Council argueing about
whether to post an "Entering Los Angeles" sign at the north end or the
south end of I-5...
                                                      _
Now, does that mean we should add named loops to C?  me genoito!
I don't think you should turn C into Ada*, for two reasons:

    1) Those who think they don't like Ada will think they won't like C.
       (Yes, that's what I meant to say.)
    2) Those who think they like Ada will already have switched to Ada.
       (Yes, yes, I know.  Hope springs eternal...)

For all her faults, Ada knows an abstraction when she sees one.  C is easy,
but a clever lady is worth waiting for.

Larry Wall
{allegra,burdvax,cbosgd,hplabs,ihnp4,sdcsvax}!sdcrdcf!lwall

*Ada iartoUSDOD(AJPO).

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (10/17/84)

The "break looplabel;" and "continue looplabel;" proposals should
not be added to the C language because they provide no additional
functionality but complicate compilation.

As has been repeatedly pointed out in this debate, they are not any
clearer than similar use of "goto label;".  Part of the spurious
argument to the contrary assumes the silly K & R brace conventions
are being used (sorry, guys, you're still my heroes).  Tell me how

	while ( condition )
	    {
		...
		if ( emergency )
		    goto forward;
		...
	    }
    forward:

is any harder to comprehend than

    backward:
	while ( condition )
	    {
		...
		if ( emergency )
		    break backward;
		...
	    }

Unless the proposal is combined with outlawing "goto", nothing is
gained by it.  However, the ANSI committee better not outlaw "goto"
since a large amount of existing C code, including a few UNIX system
utilities, would be broken by this.  Sure, one could rewrite code
like

    again:
	...
	if ( this_one_not_it )
	    goto again;
	...

to use some other looping mechanism, but the point is not to force
the massive amount of rewriting that this would entail.  Otherwise
non-standard compilers are going to be maintained indefinitely
anyway, which defeats the purpose of trying to outlaw "goto".

ron@brl-tgr.ARPA (Ron Natalie <ron>) (10/17/84)

> Gee, I thought everyone knew that the most general structured loop is
> 	startloop
> 		...
> 		on condition (...) leaveloop
> 		...
> 	repeatloop

Gee, finally someone brought up the world-famous

	do  {
		...
	} while {
		...
	}

loop.

-Ron "DOD Committee to Stop ADA" Natalie

crm@duke.UUCP (Charlie Martin) (10/18/84)

While I thought the referenced article was pretty good all-in-all,
the "managers, students, and other children" flame was low.

I used to be a manager, I'm now a student, I'm *THOROUGHLY*
conversant with the issues involved in Structured Programming
(and what about the cognative psychology issues?  We haven't
covered those yet...) and I firmly believe that those
people who have been proposing the labelled-loop idea have
string and reasoned opinions for their obviously incorrect
opinions.
          ( what is the net-glyph to indicate a sarcastic tone?)

So cool it on the "children" bit, OK?

Charlie Martin
(...mcnc!duke!crm)
		
=== improv signature line ===

		I am NOT a CHILD! I am a Software Engineer!

=== end sig ===

arnold@ucsfcgl.UUCP (Ken Arnold%UCB) (10/23/84)

> ...
> 
> For stand-alone completeness, we're talking about leaving nested loops as
> follows:
> 
>      label:
> 	for (i = 0; i < n; i++)
> 	{       ...
> 		for (j = 0; j < m; j++)
> 		{       ...
> 			if (error)
> 				break label;
> 		}
> 	}
> 
> Jim Gillogly            {vortex, decvax}!randvax!jim

Under this proposal, what does the following code do:

		if (condition)
			goto label;
		...
	label:
		for (i = 0; i < n; i++)
		{       ...
			for (j = 0; j < m; j++)
			{       ...
				if (error)
					break label;
			}
		}

Does the "goto label" go to the top of the for loop, while the "break
label" goes to the bottom?  Or is this semantically incorrect code,
which the compiler should complain about?

What this shows is that we are really talking about two seperate
things, both designated by "<identifier>:".  In C currently, this is a
marker in the code to name a place where control can be transfered.
The proposed addition would use the same syntax to name a loop so that
"break" and "continue" statements can make reference to it.  These two
meanings are not entirely compatible.

So what does it mean to "goto" a block?  Does it mean to go to the
first executable statement inside the block?  Does it mean to go to the
controlling statement of the block (in the above example, to "for (i =
...)") if it has one.  (Note that blocks can exist without controlling
statments; are such blocks nameable, "break"- and "continue"-able?).
And, even with such questions resolved in some fashion, how is the
compiler to know whether "<identifier>:" is a label or a block name?

I will say that I do not like the proposal (if you couldn't have
guessed), but I would like to know precisely what it is I don't like
:->.  I have always wanted a nice way to get out of such nested loops,
but I haven't seen one yet that is as clear as a goto with a good label
name.  And, I might warn those of you who find goto's inherently evil,
that even were this accepted, there are still areas where (at least in
C) a goto is the clearest way to code something, so "goto"s will still
be used, even by style-conscious structure freaks like me.

		Ken Arnold

stanton@fortune.UUCP (W. Dean Stanton) (10/23/84)

> > Gee, I thought everyone knew that the most general structured loop is
> > 	startloop ...  on condition (...) leaveloop ... repeatloop
> Gee, finally someone brought up the world-famous
> 	do  { ...  } while { ...  } loop.
> -Ron "DOD Committee to Stop ADA" Natalie

You probably wanted an expression after "while":
	do <statement> while (expression) <statement>
and might have also thought of:
	do <statement> until (expression) <statement>

An interesting generalization of if-then-else, while, and do-until
(even more general than C's for :-) appears in CACM, Aug. 1983 (vol. 26,
number 8), page 572:

	"A Generalized Control Structure and Its Formal Definition"
	by David Lorge Parnas.

The idea was to define a structured "algorithm".  The compiler (or whatever)
can generate whatever gotos are necessary to implement it. 

My sample C syntax for the "it" (iterate) command follows.  Read "it" as
"iterated-if", "then" as my arrow-substitute, *done* as my substitute
for a downward-arrow meaning all done with this "it" (don't iterate), and
*loop* as my substitute for an upward-arrow meaning iterate back to the
first test after "it", "elseif" was chosen to imply that you can string as
many of these as you wish off of one "it", "else" (a la default) is always
taken if you no earlier branch was taken.  [I'm quoting, I can edit it]:

	-- read until "success" but at most numtry times
	count=1;
	read(raw_data, success);
	it	(success)		then	true_data=FUNC(raw_data) *done*
	 elseif	(count < NUM_TRIES)	then	read(raw_data, &success);
	 					count++;		 *loop*
	 else								 *done*
	ti;

If you can't tell, when you it *loop*, you (dare I say it?) go-to the "it".
When you it the *done*, you go-to the ti.  If the redundant calls to read
bother you, too, they fix it with a compile-time flag, "init" (meaning,
"first time through the loop") and even "non init" ("any time except first"):

	-- read until "success" but at most numtry times
	-- COR is conditional || operator (does not evaluate rest unneccessarily
	count=0;
	it	(init COR (not success) && count < NUM_TRIES)
	 				then	read(raw_data, &success);
	 					count++;		 *loop*
	 elseif	(success)		then	true_data=FUNC(raw_data) *done*
	 else								 *done*
	ti;

The compiler handles the "init" by building an initial branch to the read.
Later loops return to the (not success) test.  Neat, huh?

				- W. Dean Stanton, Graphics Software
UUCP:	{decvax!ihnp4,ucbvax!amd,hpda,sri-unix,harpo}!fortune!stanton
USPS:	Fortune Systems Corp, 101 Twin Dolphin Drive, Redwood City, CA 94065
Phone:	(415) 594-2835
"A standard can always be improved. 
 But it won't be; this is why it is a standard." - A. Lesea & R. Zaks

chris@hwcs.UUCP (Chris Miller) (10/24/84)

In all the discussion on the merits and/or degree of structuredness of
constructs such as "break <unsigned integer>" or "break <label>" I have
not yet seen anyone observe that C ALREADY has a partial mechanism for
getting out of several nested loops without using a GOTO - it is
called "return"!

Example (using current C - translate ad lib. to your favourite syntax,
	and make identifiers unique within 6 chars :-)):

	level_1:
		while (condition_1)
		{
			while (condition_2)
			{
				while (condition_3)
				{
					switch (condition_4)
					{
					case AGAIN:
						goto Cont;
						/* I.E. continue level_1 */
					case FINISHED:
						goto Done;
						/* I.E. break level_1 */
					default:
						...
					}
				}
			}
	Cont:
		}
	Done:
Becomes:

	level_1(/* Parameters from current environment */);
	...
level_1(/* Parameters */)
{
	while (condition_1)
		if (level_2(/* Parameters */) == Done)
			return;
}
level_2(/* Parameters */)
{
	while (condition_2)
	{
		while (condition_3)
		{
			switch(condition_4)
			{
			case AGAIN:
				return Cont;
			case FINISHED:
				return Done;
			default:
				...
			}
		}
	}
	return Done;
}

If you want multi-level breaks/continues, it is even possible to return
a count indicating how many levels of loop are to be exited.

Let me defend myself instantly from rising hackles and cries of
"Efficiency!".  If you really have a collection of nested loops, then
in most cases, the cost of starting up the outer ones is small compared
with the cost of repeatedly executing the innermost one.  It may
therefore not be altogether unreasonable to parcel the whole lot up as
a separate function; it is likely in most cases to be a great deal more
readable that way, as well.

Lest anyone still be inclined to flame, a few more points:

1.  I am NOT saying that the above is "more" or "less" structured than
    any other proposal.  Simply wrapping things in procedures does not
    automatically render them structured, modular, maintainable,
    readable, or anything else!
2.  I AM pointing out that if you want to write unstructured code in C,
    you don't even need the existing "goto", "break", or "continue"
    statements - "return" is quite sufficient (let alone "longjmp",
    "exit", or, if you want to be truly obscene, "kill" to transfer
    control to a routine which has been set up for signal trapping :-)).
3.  I am NOT seriously advocating the above translation as a general
    technique - often a solution with "goto" is perfectly appropriate
    and comprehensible.
4.  I do not believe that "goto" should be banned from C (on the principle
    of not breaking existing software), and on the whole do not favour
    introducing unnecessary further constructs - if there had never been
    a "goto" in C to start with, things would be different, but there was
    so they aren't.
5.  The REAL problem with any construct, structured or otherwise is that it
    becomes hard to read if applied to too large a physical scope (very large
    loop bodies, distant targets of "break", etc.).  On C compilers which
    support multi-line macro definitions (i.e. V7 and most later ones) a
    considerable gain in clarity, at no cost in efficiency, can be gained
    by packaging loop bodies as macros, even if they only appear once in
    the code.
6.  I am a computational atheist.
-- 
			Chris Miller
			Department of Computer Science
			Heriot-Watt University
			...!ukc!{edcaad,west44}!hwcs

lambert@mcvax.UUCP (Lambert Meertens) (10/25/84)

:
I propose the creation of a new newsgroup, "net.lang.c.nestedloopbreak".
The last selector is a bit of a finger twister; better suggestions, anyone?
A major advantage of this newsgroup would be that no-one (unless s/he
desired so) would have to wade through all this stuff of marginal
interest in net.lang.c to get to the really interesting discussion of
how to get out of deeply nested loops. (How did we get in in the first
place? :-)
Another possibility is setting up "mod.lang.c.nestedloopbreak". I am
willing--somewhat reluctantly, since fascism is not exactly
fashionable--to serve as the moderator of such a group.
-- 

     Lambert Meertens
     ...!{seismo,philabs,decvax}!lambert@mcvax.UUCP
     CWI (Centre for Mathematics and Computer Science), Amsterdam

stuart@ncoast.UUCP (Stuart Freedman) (10/29/84)

> I propose the creation of a new newsgroup, "net.lang.c.nestedloopbreak".
> The last selector is a bit of a finger twister; better suggestions, anyone?
> A major advantage of this newsgroup would be that no-one (unless s/he
> desired so) would have to wade through all this stuff of marginal
> interest in net.lang.c to get to the really interesting discussion of
> how to get out of deeply nested loops. (How did we get in in the first
> place? :-)

Why not just use rn?  I think that this program has most of what we need in
order to make a newsgroup serviceable to everyone by deleting things one
doesn't want to see.  Now just watch people start using creative subject
lines, just so that we will have to see their postings!!!

-- 
Stuart Freedman				decvax!cwruecmp!ncoast!stuart
Case Western Reserve University

smk@axiom.UUCP (Steven M. Kramer) (11/02/84)

Besides not using goto for structured reasons, I don't use it because
many optimizers barf when it is used and the resulting code runs
slower.
-- 
	--steve kramer
	{allegra,genrad,ihnp4,utzoo,philabs,uw-beaver}!linus!axiom!smk	(UUCP)
	linus!axiom!smk@mitre-bedford					(MIL)

jim@ISM780B.UUCP (11/03/84)

>While I thought the referenced article was pretty good all-in-all,
>the "managers, students, and other children" flame was low.

It was "managers, students and other children, ..." (note the commas)
which is quite different.  If you aren't a child, or a manager who is
technically uneducated, then this doesn't apply to you, so why get upset?
My point was that there _a_r_e many people on the net who are very inexperienced
and/or uneducated and they would do well to temper their opinion of their
own opinions, and do some reading in the subject.  I was not stating any
opinion about the value of structured programming or of structured constructs
per se (in fact I regard them highly); rather, I was talking about them in the
context of the C standardization effort specifically, and in the context of
sweeping generalizations made about stuctured programming by _s_o_m_e on the net.

-- Jim Balter, INTERACTIVE Systems (ima!jim)

crm@duke.UUCP (Charlie Martin) (11/05/84)

Contrary to your note, there is no difference between
"managers, students, and other children" and
"managers, students and other children" -- they have the same
meaning.  Check for example Fowler's book on English Usage or
a modern style manual, like that of the New York Times.

In addition, I have been a manager and am now a student and I still
feel pretty certain that I am included in the class to which you
ascribed a childish lack of knowledge.
-- 


			Can you say "classical fallacy?"
			Good! I *knew* you could.

				Charlie Martin
				(...mcnc!duke!crm)