[net.lang.c] using break <label> instead of goto <label>

guy@rlgvax.UUCP (Guy Harris) (01/10/85)

> Please don't attribute to me something I didn't say. I was not advocating
> the elimination of goto's from C, but felt the put-down of the idea of break
> <label> might not have been well thought out.

But what Ron was saying was that if you don't eliminate "goto", "break <label>"
just amounts to "semantic sugar" for "goto <label>"; if you want to discourage
people from using "goto" you can just put

	#define	breakloop	goto

or something like it in a header file.  Putting in a "break" statement which
acts exactly like "goto" but which is only accepted by the compiler in certain
contexts doesn't really add anything to the power of the language.

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

mjl@ritcv.UUCP (Mike Lutz) (01/11/85)

> ...  Putting in a "break" statement which
> acts exactly like "goto" but which is only accepted by the compiler in certain
> contexts doesn't really add anything to the power of the language.
> 
> 	Guy Harris

I disagree with Guy on this one (exceedingly dangerous, if you know
what I mean, and I think you do :-).  If indeed the break <label> is
added so that a) the <label> must be associated with a control construct in
which the break is nested and b) causes execution to start with the
first statement following this construct, then indeed it is different
from (and, I argue, a useful alternative to) goto <label>.  Guy is
right - break <label> does not extend the power of the language; if
anything, it limits it (or, better yet, controls it).

The altered semantics *are* important.  Sure, the documentation effects
can be achieved by strict adherence to programming conventions and the
use of a #define like the one Guy proposed.  However, the error
detection possibilities are every bit as important (I vaguely remember
making an error long ago), and the limited form of goto can turn
difficult to diagnose run-time errors into compile-time errors.

All of this ignores, of course, any assessment of the problems of
incorporating this facility in C relative to its worth.  I've no
illusions about the difficulty, especially when you realize that all
labels are potential targets of a goto but some are also possible
referents of the new break.  But I was addressing the absolute utility
of the construct, rather than its relative utility when considering
the engineering problems of such a retrofit.
-- 
Mike Lutz	Rochester Institute of Technology, Rochester NY
UUCP:		{allegra,seismo}!rochester!ritcv!mjl
CSNET:		mjl%rit@csnet-relay.ARPA

Doug Gwyn (VLD/VMB) <gwyn@Brl-Vld.ARPA> (01/11/85)

I really think the discussion of "goto" in C is overblown.
I just grepped through over 6,000 lines of production C code
and found one instance of goto used as an EOF exception escape
and 7 instances (in the same module) of gotos to a common error
return.  Not a single goto for any other purpose, including
multi-level breaks.  I would argue that this code exhibits
why "goto" can be useful and that the "dangerous" uses of it
can be totally avoided.  Perhaps programmer education is more
important than changing the language.

mat@hou4b.UUCP (Mark Terribile) (01/11/85)

>But what Ron was saying was that if you don't eliminate "goto",
>"break <label>" >just amounts to "semantic sugar" for "goto <label>";
>if you want to discourage people from using "goto" you can just  . . .

Not quite.  You see, if you follow out this philosophy, we can do away with
for(;;) and while() and the else in if()-else ... and compound statements
too.

An upholsterer's tack hammer is no more powerful than a 15-lb maul.  Why use
the tack hammer?  Because it is suited to the job.  More specifically, it lets
you put the force you need where you need it without scattering that force
everywhere else.

The labelled break allow you to get out of (i.e. go to just below) a loop
without making it possible to get there from anywhere else.  Very important.

Viewed differently, the labelled break is the addition of a (presumably) needed
capability to the thing that needs it (the loop and switch statements)
without making the remainder of the program unsafe.
-- 

	from Mole End			Mark Terribile
		(scrape .. dig )	hou4b!mat
    ,..      .,,       ,,,   ..,***_*.

MLY.G.SHADES%MIT-OZ@MIT-MC.ARPA (01/12/85)

> Perhaps programmer education is more important than changing the language.

at last somebody who understands.  it's the programmer who writes the
damn code not the language compiler.

                            shades@mit-oz

Doug Gwyn (VLD/VMB) <gwyn@Brl-Vld.ARPA> (01/12/85)

People keep hoping for the magic panacea that will ensure automatic
correctness of their programs.  Last year it was Ada; this year it
is knowledge-based program writing systems; next year it will
be something else.  I keep seeing the same ideas attempted over and
over as the years go by.  The one idea that works, to think clearly
and carefully, has not found much favor.

guy@rlgvax.UUCP (Guy Harris) (01/13/85)

> Not quite.  You see, if you follow out this philosophy, we can do away with
> for(;;) and while() and the else in if()-else ... and compound statements
> too.

Yes, but

	while (<condition>) {
		...
	}

is easier to read and write than

loop:
	if (!<condition>)
		goto endofloop;
	...
	goto loop;

while one "ed" command, or one #define, can turn

	while (<condition>) {
		...
		breakloop label;
		...
	}

label:

into its "goto" equivalent.  (Putting the label at the beginning of the
loop would make that harder, but it would also make it harder for the reader
to find the point that the "breakloop" goes to.

> The labelled break allow you to get out of (i.e. go to just below) a loop
> without making it possible to get there from anywhere else.

Except for one problem: nobody's proposed deleting "goto" from the C language
(and anybody who proposes it should personally have to rewrite every program
that uses it safely).  As such, C *will* let you get anywhere from anywhere
else (within a function body, at least) even with the addition of the "break
<label>" construct.

If we're designing a *new* language, we might consider fancier "break"
statements and no "goto" (although even "break" and "continue" can impair
the readability of a program).  Since C already has a "goto", though, and
it's impractical to eliminate it, I don't think "break <label>":

	1) makes the language easier to write in
	2) makes it easier to read programs
	3) makes it easier to verify programs
	4) makes it easier to optimize programs

I presume that any flowgraph that for a program written with "safe" "goto"s
can be rewritten either with "break <label>" and "continue <label>", or by
node splitting (i.e., where "goto" is used as a way of folding code).  This
is probably close to a formal statement of my notion of "safe" "goto"s, and
probably close to most other people's notion as well.  If so, you can
formally eliminate "goto"s from programs, so the only question that comes up
is whether the informal aspects of readability and writability are affected
by the addition of "break <label>".  I don't think it's affected enough
to make it worth the trouble of adding "break <label>" to the language.  As
I've said, even unlabelled "break" and "continue" statements can impair
readability; it's harder to find the end of a loop when examining its innards
in detail than when looking at the loop as a whole, so that it is less obvious
what the flow of control is when looking at the "break" in

	while (<condition>) {
		...
		if (<condition 2>)
			break;
		...
	}

then when looking at the "while" loop as a whole.  (I.e., it's more obvious
that control flows from the code before the closing "}" to the condition
test on the "while" line than it is that control flows from the "break"
statement to the code after the closing "}".)  I would still use a "break"
in this case, out of habit and out of a partially-superstitious desire to
avoid a "goto", even though putting in a label might make it easier to
see where the "goto" goes to; also because it means I don't have to invent
a name for the label.  Putting in a "break <label>", however, means I have
to invent a label.  And if the label goes at the beginning of the loop,
rather than the end, you have to search for the label and then search for
the end of the loop to figure out where it goes.  This is becoming a
problem in the psychology of programming; does anybody have any hard evidence
for or against the proposition that labelled breaks - of either kind - make
it easier to program?  If not, we're all trading anecdotal evidence, and
the horse's corpse is beginning to look a bit messy...

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

Tony Li <Tli@Usc-Eclb> (01/13/85)

    From: Doug Gwyn (VLD/VMB) <gwyn at BRL-VLD.ARPA>

    People keep hoping for the magic panacea that will ensure automatic
    correctness of their programs.  Last year it was Ada; this year it
    is knowledge-based program writing systems; next year it will
    be something else.  I keep seeing the same ideas attempted over and
    over as the years go by.  The one idea that works, to think clearly
    and carefully, has not found much favor.

It has not found much favor because it does not work well.  Consider
the lifecycle of an average software package.  Currently, for *ANY*
software package, you should expect to spend at least half of your
budget on maintenance.  

The hope is that the development of a automatic correct program
generator would help to eliminate much of this maintenance cost.  

Cheers, 
Tony ;-)

MLY.G.SHADES%MIT-OZ@MIT-MC.ARPA (01/13/85)

	agreed that a significant amount of all software production is
spent doing simple maintenance i still agree with doug gwyn that clear
thinking (i.e. good old common sense) would improve correctness,
maintainability, and reduce cost more than compiler enforced rules.
	something that i have noticed out in the "real" world is that 
the more complex the language rules, no matter how rigidly enforced, 
the more drastic the increase in the time necessary for the 'average' 
(six month matchbook cover) programmer to produce even the simplest of
programs (unfortunately these are also the ones least likely to use
their common sense).  it cuts both ways. rigidity and higher costs in
development or looseness and higher maintenance costs.  
	one major problem that i commonly see is that the more junior
the programmer the more likely he/she/it will be doing the
maintenance. this is a serious problem.  the person with the least(!)
experience is given the job where that person can do the most damage.
(sigh)

	anyway when it gets down to brass tacks my objection to break
label is mainly on the grounds that enforcing the construct properly
would be adding a grievous burden upon the compiler.  if the label is
placed before the block that it escapes the compiler must generate two
internal labels for that label, one for the break and one for a
possible goto.  this is of course only a hazard on smaller machines
supporting small symbol tables but it still is an unecessary 

Tony Li <Tli@Usc-Eclb> (01/14/85)

Whoa!  I'm not out to automate current design practices.  I'm much
more interested in providing a NEW design methodology whereby the
compiler (or some other entity - like lint for C) goes through and
either (1) proves your program correct or (2) derives a provably
correct program from a proof of an algorimth.

Work is currently being done on both these topics on a very small
scale, and things look quite promising except for the fact that doing
these things take mega-cycles.  Once we know enough to where we could
make things efficient, this should greatly simplify the software
design process.  Ultimately, it might be possible to have the designer
just state the goals, and let the system generate all of the code,
e.g. "Sort these numbers, and write them to tape as an ANSI file
FOO.BAR".  

The heuristics are involved when we try to generate "good" code for a
specification that has a little leeway.  Since there are lots of
possible implementations, and we don't have the opportunity to look at
all of them, we need a heuristic to help decide the implementation.

So actually, I guess that I'm in favor of giving the programmer a lot
of assistance in 'thinking logically and clearly'.  Currently, this is
a tough proposition, and is done by a very few people.  I'm hoping
that this would mean that new programmers would have to learn very few
new rules (mostly Boolean logic - that's not unreasonable, is it? ;-).
And with that, you could dispose of a lot of nitpicking rules that we
have now.

[End of digression, back to reality]

As to break <label>, I have mixed feelings.  Yes, it's a cleaner
feature than a goto.  Unfortunately it's not trivial to implement, and
it's a new feature, which means that it would wind up in C from now to
eternity, along with 'goto'.  I'm not sure that the gain makes up for
the burden on the language design.

Cheers, 
Tony ;-)

MLY.G.SHADES%MIT-OZ@MIT-MC.ARPA (01/15/85)

	when you but in that form (new design methodology) i tend to
agree. proving correctness would be nice but we still end up with the
problem of providing possibly deleterious additions to an existing
language (break <label>).
	the c compiler that i use at home is decus c on a small(!!) 11
and at work it is the honeywell mod400/dps 6 c compiler basically
derived from unix's, i also use the pcc compiler for tops-20 here at
oz. all of them are excessively slow and in the case of my home
machine limited in symbol table size.  anything that degrades
performance in this case without being a significant improvment to the
language as a whole would be fiercely resented.

	sorry about the incomplete previous message i sent that
accidentally but since the discussion has passed on i will not finish it.

rpw3@redwood.UUCP (Rob Warnock) (01/15/85)

+---------------
| People keep hoping for the magic panacea that will ensure automatic
| correctness of their programs...
+---------------

Quite so, Doug. Also see the current? issue of "Whole Earth Review",
on the theme of "Computer As Panacea: All Panaceas Turn To Poison".

+---------------
|                       ... The one idea that works, to think clearly
| and carefully, has not found much favor.
+---------------

There is a reason. It is painful to do so until one has been trained
(disciplined) enough so that the results of NOT doing so are more
painful than the thinking. The training takes a long time. It too
is painful. There are not many teachers/mentors/gurus/old-timers
around who can help us through the rough stages, and doing so on
one's own is not likely (though possible). The sage advice printed
in books pales against your bosses' demands for "More!" and "Now!".
It requires an exceptionally hospitable environment (such as being a
support staff member in a graduate or post-graduate research atmosphere).

I remember the first time I seriously tried to write a program that would
be "perfect", that is, to compile and execute correctly the first time
it was submitted to the system.  (I had gotten all excited reading Djikstra
or somebody, and had this wild hair about "zero defect" programming.) I was
just switching from MACRO-10 (the assembler) to BLISS-10 (which has no "goto")
for doing systems programming, and was writing a "stdio"-like I/O package.
(BLISS-36 now comes with "EZIO", but it didn't exist then.) The specification
was fairly simple. I wanted the program:

	MODULE TEST =
	BEGIN
	REQUIRE	IOX.REQ;	! These days we say "#include <stdio>"

	LOCAL	C;

	WHILE	(C = GETC()) NEQ IOX_EOF
	DO	PUTC(.C);

	END
	ELUDOM

to give the user a standard prompt (using SCAN/WILD, for you TOPS-10 folk),
accept a command string of

	*OFILE=IFILE1,IFILE2,...

and do "sort of the same as" the UNIX command "cat ifile1 ifile2 ... >ofile".

The exercise in fact succeeded, but it was *P*A*I*N*F*U*L*. (And I don't
just mean giving up the "goto"!) The only way I managed to do it was to
write the entire program on paper, in a notebook, saving all versions and
notes and scratchings, and REWRITING each module in a clean form for each
step of refinement or backup. (Yes, I had to back up a lot.) A couple of
times I started typing it in, but realized there were pieces missing, and
went back to the notebook. That was possibly the most painful part -- staying
away from the machine. But it paid off. When finally typed in (and printed
out BEFORE compiling and desk-checked and corrected), it compiled and ran.

I am sorry to say that many times in the years since I have allowed myself
to become seduced again by the very addictive nature of working "on line",
sometimes to the extent that I could not consider working if the computer
was "down" (even when what I had to do could be done on paper!). But sometimes
when the project was just too big for me to hold in my head or on the 25 lines
of the screen, or when I just HAD to get it done right and on time, I would
revert to the "primitive" methods of pencil and paper, of "design before code".

I feel I have learned several lessons:

#1: "Zero defect" development of software is possible, but it requires
    a severe discipline in how one works.

#2: Even for people who know #1, and who understand what it implies, it is
    never easy. Constant little temptations or pressures arise to try to
    shortcut the necessary steps. It never gets any easier. The whole
    environment must support the effort.

#3: Knowing #2, the only way we will do it is if we realize the cost of NOT
    doing it (bugs we'll never find, slipped schedules, cost overruns, and
    maintenance headaches).

#4: Most software development organizations ("Management") are not willing
    to face #3 (see any book on Quality Control), so since #2 is still true,
    "zero defects" becomes impossible, or at least unlikely. Even individuals
    who understand #1, #2, and #3 find difficulty in consistently applying
    their understanding on problems that seem "too small" or "not worth it"
    (i.e., we ignore the cost to ourselves in getting sloppy in our discipline).

#5: Both large organizations and individuals tend to severely underestimate
    the scope of tasks, thus reinforcing #4.

How does this concern net.lang.c? In my experience, C is "good enough"
as it is. The above considerations far outweigh the minor wrinkles the
net has seen discussed recently (e.g. how to initailize unions, "goto"
versus "break" versus "leave"). Yes, C can be tuned a bit, and people
would benefit from it, I suppose.

(I favor the "leave <labelled-block>", myself, but frankly I don't recall
having ever used a "goto" in C, for ANY purpose, so who am I to say?) 

But to some extent, such discussions of the effect of programming constructs
on program correctness are similar to discussing the effect of the color of
automobile dash panel indicators on traffic safety while driving 90 miles
an hour in the rain, with one hand on the wheel, drinking whiskey, with the
radio turned up to deafening, your headlights off, and no seatbelt.

(While the sarcasm of the previous sentence may be a bit heavy, consider
the New England pediatrician who completely gave up his medical practice
of many years and went to work lobbying for infant car seats. He had looked
up one day and discovered that preventible auto-accident injury killed more
of his young patients than ALL other causes COMBINED, including disease and
all non-auto accidents.)

+---------------
|                       ... The one idea that works, to think clearly
| and carefully, has not found much favor.
+---------------


Rob Warnock
Systems Architecture Consultant

UUCP:	{ihnp4,ucbvax!dual}!fortune!redwood!rpw3
DDD:	(415)572-2607
USPS:	510 Trinidad Lane, Foster City, CA  94404

henry@utzoo.UUCP (Henry Spencer) (01/15/85)

>     People keep hoping for the magic panacea that will ensure automatic
>     correctness of their programs.  Last year it was Ada; this year it
>     is knowledge-based program writing systems; next year it will
>     be something else.  I keep seeing the same ideas attempted over and
>     over as the years go by.  The one idea that works, to think clearly
>     and carefully, has not found much favor.
> 
> It has not found much favor because it does not work well.  Consider
> the lifecycle of an average software package.  Currently, for *ANY*
> software package, you should expect to spend at least half of your
> budget on maintenance.  

I fail to see how this contradicts anything Doug said.  Unless, of
course, you add an implicit "...and your maintenance programmers will
be dolts, incapable of clear and careful thought"!
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

ron@brl-tgr.ARPA (Ron Natalie <ron>) (01/15/85)

> All of this ignores, of course, any assessment of the problems of
> incorporating this facility in C relative to its worth.  I've no
> illusions about the difficulty, especially when you realize that all
> labels are potential targets of a goto but some are also possible
> referents of the new break.  But I was addressing the absolute utility
> of the construct, rather than its relative utility when considering
> the engineering problems of such a retrofit.
> -- 
Agreed.  I'm not saying break-to-label isn't a good thing for some language
to have.  There's a lot of things we could put into languages if we were
starting over.  What I'm arguing against is making frivolous changes to an
existing language.  So far nearly all of the proposed extensions that the
committe has been proposing, do not change the language when it can be
avoided.

If we trully want to be structured we'd get rid of "break" and "goto"

-Ron

ron@brl-tgr.ARPA (Ron Natalie <ron>) (01/15/85)

> I really think the discussion of "goto" in C is overblown.
> I just grepped through over 6,000 lines of production C code
> and found one instance of goto used as an EOF exception escape
> and 7 instances (in the same module) of gotos to a common error
> return.  Not a single goto for any other purpose, including
> multi-level breaks.  I would argue that this code exhibits
> why "goto" can be useful and that the "dangerous" uses of it
> can be totally avoided.  Perhaps programmer education is more
> important than changing the language.

Yes, this is an indication that the reason most good programmers
place non-structured constructs in their code is to avoid code
duplication.

-Ron

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (01/16/85)

> ... this is an indication that the reason most good programmers
> place non-structured constructs in their code is to avoid code
> duplication.

Or to handle errors and exceptions that cannot be reasonably
treated by the main program logic.  The alternative often is
to ignore these, with loss of robustness, or to carry around
lots of silly state flags to be tested in loop conditions.