[comp.lang.c] goto's in C: an opinion...

weiss@bigburd.PRC.Unisys.COM (Tom Weiss) (07/15/87)

Since now appears to be the time to express opinions about
style/clarity, I would like to address my own pet peeve: the goto
statement.

There are very few legitimate uses for the goto statement, and C
provides alternates for most of them.  While it is true that these
alternates are no less evil than goto viewed from a structured
programming perspective, at least they are more readable.

Since C provides the break statement to break out of a loop, the
continue statement to jump back to the top of a loop, the return
statement to immediately exit a function, and access to system calls
(e.g. exit) that can terminate execution in error handling functions,
there are few 'legitimate' uses for goto.  The only one that
immediately comes to mind is breaking directly out of a
multiply-nested control structure.

Once I was involved in rewriting a piece of code which contained a
goto.  The code consisted of a large loop containing switch and
if/else statements.  When I first rewrote it, I eliminated the
original goto, but introduced two of my own!  I then took a close look
at what was really going on.  The original goto was used to jump
forward into the middle of an if/else construct.  When I rewrote the
code, I basically added features, without changing the overall control
flow.  Though the original goto disappeared, I introduced more goto's
to keep in tune with the original structure.  When I saw what I had
done, I knew something was very wrong, and I decided to see what would
happen if I rewrote the code to remove the goto's.  I originally
expected that I would wind up making some new functions to be called
from the loop.  As it turned out, all I had to do was change the order
of tests in the loop (this involved eliminating the switch).  In
short, poor logical design had necessitated the original use of goto,
and encouraged more goto's in expanded versions.

My point is that 99% of the time I see a goto in a C program, it is
not there for any good reason.  Usually goto's are used to make loops
or jump around within a chunk of code that has poorly structured
control flow.  I do not mean to say that programmers who use goto's
are lousy programmers, merely that they have gotten into a bad habit
that should be broken.

hwe@beta.UUCP (Skip Egdorf) (07/17/87)

In article <3289@bigburd.PRC.Unisys.COM>, weiss@bigburd.PRC.Unisys.COM (Tom Weiss) writes:
> 
> Since now appears to be the time to express opinions about
> style/clarity, I would like to address my own pet peeve: the goto
> statement.

I love your comments Tom, now just be a bit more assertive...

> 
> There are very few legitimate uses for the goto statement,

  There are NO legitimate uses for the goto statement...

> ... C
> provides alternates for most of them.  While it is true that these
> alternates are no less evil than goto viewed from a structured
> programming perspective, at least they are more readable.

A large myth from the 70's, where structured programming was viewed
as "no gotos", was that forward jumps out of loops were not structured.
This is not true. A break transfers control to a known place and provides
just as structured a piece of code as a while leaving the loop on a false
condition.

I have been in "discussions" with programmers who claim that some piece of
code just written, containing only gotos as structuring elements, is
a structured program because it uses only proper constructs (implemented
with gotos) of if-then-else, looping, and sequences. This argument is
valid as far as it goes. Two problems exist with programs of this form,
or programs with ANY gotos.

 1. The major amount of effort in any production code is maintaining that
    code. As programmers modify code with gotos, lack of understanding
    of the entire structure of the program leads to local modifications.
    Additional jumps to local labels, and additions of code that span
    earlier structures not visible due to the goto-implementation
    cause Entropy increase, and the code becomes unstructured.

 2. While the author claims that the program is structured, no compiler
    can verify that the gotos are used to implement only the structured
    programming constructs. I don't believe my own assertions about the
    correctness of some un-verified piece of my own code. I will not
    believe someone else's.

> 
> Since C provides the break statement to break out of a loop, the
> continue statement to jump back to the top of a loop, the return
> statement to immediately exit a function, and access to system calls
> (e.g. exit) that can terminate execution in error handling functions,
> there are few 'legitimate' uses for goto.  The only one that
> immediately comes to mind is breaking directly out of a
> multiply-nested control structure.

And if such a structure is used, it can ALWAYS be improved by removing
some of the structure to a sub-function.

> 
> Once I was involved in rewriting a piece of code which contained a
> goto.
> ... story about re-doing a code containing gotos, and improving it...
>

Again, two points

1. When I moved from fortran and assembler to a MULTICS and PL/I, I found that
   I had stopped using gotos. I didn't do this on purpose. I just found
   that I never reached a place where I needed one. I began examining
   lots of other code and re-doing it without gotos. Sometimes this was
   hard, and involved a total re-design of the code (see below).
   I did find that in EVERY case the code got more understandable,
   more efficient, and shorter in both source and object form. EVERY
   case was a triple win, with no loss. I have never found a case
   where someone could provide me with a goto'ed code, and I could not
   improve it in all three areas. Anyone reading this who sends me some
   piece of garbage to improve, please understand that it will goto(sic)
   /dev/null. The reson is...

2. Just removing gotos by simple restructuring techniques is not sufficient.
   (If it were, a compiler could do it. Recall that this is the general
    case. Not just a few special cases, such as handeled by programs
    like 'struct'.)
   Goto lovers find it fairly simple to come up with code fragments that
   require extra state variables or extra levels of procedure call to
   improve. My removal of gotos sometimes required my return to the
   functional specification of the system and a complete re-implementation.
   (and yes, I re-implemented as little as necessary, so that this did
   not skew the results too badly. I do believe that the re-implementation
   affected only the goto-ness of the program.) I finally gave up on
   this as I felt, and now feel, that any program with a goto is poorly
   designed, badly implemented, and a sign that the programmer did not
   know what was going on.

To finish up...
In 1968 Dijkstra's "gotos considered harmful" letter in CACM caused
comments like "I don't really understand what he is saying, but I am
sure that it is important...".
Computer professionals who did not wish to be branded as fuzzy-headed
ivory-tower unrealistic dreamers were forced to take a moderating
position of "gotos are bad, but a few are ok, once in a while...".

It is time to reverse this. So, to make my position clear:

In any language that supports a complete set of structured constructs,
there is NO NEED for a goto, and the statement should be removed from
the language!
Languages that do not have enough control structure should be used only
with a pre-processor (e.g. Fortran and Ratfor).

					Skip Egdorf
					hwe@lanl.gov

Since most work at Los Alamos is still fortran, I am sure that these
views are not representative of my employer. More's the s thip

edw@ius2.cs.cmu.edu (Eddie Wyatt) (07/17/87)

In an article by Skip Egdorf (hwe@beta.UUCP), Skip sez,
> There are NO legitimate uses for the goto statement...

   I sez..
   There is a whole class of problems that map very nicely into goto contructs.
They are simulation of NFAs and DFAs (ie finite state machines).

   States map very nicely to labels and transitions map very nicely into
if (input == ?) goto label.

   The most readable way one can represent the NFA/DFA is through a mesh
of gotos with a diagram of the machine in comments :-).

  For most other problems though, gotos are not need.

  I have to admit though, since my days of BASIC, I haven't used a single
goto statement.  The lexigraphical analysizers I've written, have been
simple enough that one case statement with some nicely place returns
will do the job.

-- 
					Eddie Wyatt

e-mail: edw@ius2.cs.cmu.edu

terrorist, cryptography, DES, drugs, cipher, secret, decode, NSA, CIA, NRO.

wesommer@athena.mit.edu (William Sommerfeld) (07/18/87)

In article <7571@beta.UUCP> hwe@beta.UUCP (Skip Egdorf) writes:
>  There are NO legitimate uses for the goto statement...
	.. more flaming about "goto", "break", etc.
>
>1. When I moved from fortran and assembler to a MULTICS and PL/I, I found that
>   I had stopped using gotos. I didn't do this on purpose. I just found
>   that I never reached a place where I needed one. 

Ok, here's a different opinion: gotos are useful only for jumping to
cleanup code at the end of a function or block.  This is particularly
important in kernel and daemon code, where avoiding memory leaks and
forgotten unlocks of interlocked objects means that you need to do
some cleanup before returning.  Sure, you can put all that stuff in
line before the return statement, but when you add something else
which needs cleanup to the function, you have to go through all the
error returns, and fill in the things which need allocating..  by
having one error return reached by "goto punt" or "goto bad", you put
one allocate/lock/etc call at the start of the routine, and one
free/unlock/etc call at the end.

i.e.:

frobnicate(name1, name2)
	char *name1, *name2;
{
	object *foo = NULL, *bar = NULL;
	int status;	/* return code; always set before a "goto punt" */
	foo = find_object(name1);
	if (!foo) {
		status =  NO_FOO;
		goto punt;
	}
	bar = find_object(name2);
	if (!bar) {
		status = NO_BAR;
		goto punt;
	}
	status = mush(foo, bar);
	if (status) goto punt;
	status = mush(bar, foo);
	if (status) goto punt;
	status = mash(foo);
punt:
	if (foo) release(foo);
	if (bar) release(bar);
	return status;
}

(if you replace "object" with "inode" and "find_object" with "namei",
and you've got a typical UNIX system call)

Interestingly enough, this coding style opinions evolved mostly from
looking at Unix kernel code and (get this) Multics PL/1 code that a
friend of mine was working on.

>In any language that supports a complete set of structured constructs,
>there is NO NEED for a goto, and the statement should be removed from
>the language!

What this use of the goto boils down to is an exceptional return.  
C doesn't have any kind of exception handling mechanism, which is a
part of any "complete set of structured constructs", so it is
necessary to simulate exception handling using goto.

Most multics PL/1 programs I've seen don't use PL/1 exceptions very
much; return codes and "goto PUNT" are much more common, probably for
efficiency reasons.  Exceptions are used for some really obscure
things, though.. the library routine which asks a yes-or-no question
first signals "command_query", and if there is a hander for it, it can
answer the question.  This is used by the 'answer' command, as in (to
use a UNIXy example) "answer yes fsck /dev/rra0g" [Never mind fsck -y;
this is a contrived example].  Since on Multics, I/O redirection is a
mess and pipes don't exist, "yes | fsck /dev/rra0g" is out of the
question.

					Bill Sommerfeld
					wesommer@athena.mit.edu
					...!mit-eddie!wesommer

daveb@geac.UUCP (Dave Brown) (07/18/87)

  It is as much a design problem as a style issue: the same
keyword is used to exit a switch as a loop, therefore making
it impossible to exit a loop from said switch.... Unless you 
really distort things and use continue to mean "don't break".
  B had the same problem, not unexpectedly.
-- 
 David (Collier-) Brown.              |  Computer Science
 Geac Computers International Inc.,   |  loses its memory
 350 Steelcase Road,Markham, Ontario, |  (if not its mind)
 CANADA, L3R 1B3 (416) 475-0525 x3279 |  every 6 months.

ark@alice.UUCP (07/18/87)

Skip, I suggest you read Don Knuth's article "Structured Programming
with goto Statements" in Computing Surveys (Jan 1974?).

mlinar@poisson.usc.edu (Mitch Mlinar) (07/18/87)

In article <7571@beta.UUCP> hwe@beta.UUCP (Skip Egdorf) writes:
>In article <3289@bigburd.PRC.Unisys.COM>, weiss@bigburd.PRC.Unisys.COM (Tom Weiss) writes:
>> 
>> Since now appears to be the time to express opinions about
>> style/clarity, I would like to address my own pet peeve: the goto
>> statement.
>
>I love your comments Tom, now just be a bit more assertive...
>
>> 
>> There are very few legitimate uses for the goto statement,
>
>  There are NO legitimate uses for the goto statement...
>

Hmmmm.   Methinks I smells a fanatic ...

>> 
>> Since C provides the break statement to break out of a loop, the
>> continue statement to jump back to the top of a loop, the return
>> statement to immediately exit a function, and access to system calls
>> (e.g. exit) that can terminate execution in error handling functions,
>> there are few 'legitimate' uses for goto.  The only one that
>> immediately comes to mind is breaking directly out of a
>> multiply-nested control structure.
>
>And if such a structure is used, it can ALWAYS be improved by removing
>some of the structure to a sub-function.
>

which also clearly increases the code size (even if only a little),
but let's read on

>   more efficient, and shorter in both source and object form. EVERY
>   case was a triple win, with no loss. I have never found a case
>   where someone could provide me with a goto'ed code, and I could not
>   improve it in all three areas. Anyone reading this who sends me some

Given even your rough example, you have not proven anything to me yet.

>   Goto lovers find it fairly simple to come up with code fragments that
>   require extra state variables or extra levels of procedure call to
>   improve. My removal of gotos sometimes required my return to the
>   functional specification of the system and a complete re-implementation.
>   (and yes, I re-implemented as little as necessary, so that this did
>   not skew the results too badly. I do believe that the re-implementation
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
What does this mean?  I could take this to mean the code is HARDER to read,
has LONGER source, or just plain wrong.

>
>In any language that supports a complete set of structured constructs,
>there is NO NEED for a goto, and the statement should be removed from
>the language!
>

Well, Skip, you have not given me anything concrete to work on.  Before you
get all steamed up, let me say I agree with you *in principle* and I also
strive quite hard to keep goto's out of the C code (and am over 95%
successful, if I had to take a stab at the actual stats).  However, there are
some things I think you over-dramatized:

  (1) (Sub)programs without GOTOs are NOT always more readable.

  (2) Similarly, STRUCTURED code is not always easier to read.  I have seen
some pretty STRANGE structures which are "curable" (I know you hate the use
here) by the addition of one GOTO.  I have watched programmers beat themselves
up on this one...

  (3) THERE IS *NO* GENERALIZATION THAT CAN BE MADE REGARDING CODE SIZE.  I
can give you HUNDREDS of examples (and bury your mail system :-) that
clearly show a GOTO produces less code size, and I can give you a hundred more
where STRUCTURE clearly produces the smaller code.  It is dependent upon the
function being implemented.  (Please show me how a structure made more
readable by moving a piece into a subfunction can produce SMALLER or FASTER
code.  At BEST, there is a CALL/RETURN opcode set and associated delay.)


Again, I *agree* with the principle, but be realistic!  I always strive to
dump GOTOs in favor of structures REALIZING that code size may NOT
go down, but that MAINTAINABILITY increases.  I often "kick back" code which
I feel has unnecessary GOTOs to the originator; since most of the time they
are NOT needed.  But to declare that GOTOs are NEVER acceptable is
pure horse-puckey.  (I am not sure the "grand master" was in favor of
stamping them out altogether, I *believe* he felt the way I do - it is too
easy to use GOTOs to get the code working rather than planning and 
structuring the program correctly - "GOTO disease" - and should only be
used WHERE THE CODE WARRANTS IT.)

There is a nice class of decision trees which can NEVER be implemented smaller
in a structure and and appear MESSIER when in a structure (to me anyway)
versus just a couple labels and GOTOs to "help the structure out".  I would be
happy to drop just one of these on the net if you have trouble believing me.

-Mitch

rst@think.COM (Robert Thau) (07/18/87)

In article <7571@beta.UUCP> hwe@beta.UUCP (Skip Egdorf) writes:
>In any language that supports a complete set of structured constructs,
>there is NO NEED for a goto, and the statement should be removed from
>the language!

If you mean this literally, then we don't disagree, but I'm about to
agree with you *very* heatedly.  The only language I know well which
supports a set of structured constructs complete enough that I can
entirely avoid goto's is Common Lisp (salted with some reasonable way
to handle errors, a serious omission from the standard.  BTW, I've
never used Ada).  C does handle the common cases, but there are
others...

The example everyone knows is multi-level break.  It's clearly
structured, but C doesn't have it.  (It isn't even possible to use
'break' to get out of a singly nested loop if the body is a switch
statment).  The obvious workaround is a 'goto' to a label at the end
of the loop.  The "pure" alternative is to add a bogus flag variable
which is tested as part of the loop condition.  I think this is
actually *less* clear, since an assignment to the flag has the effect
of altering flow control (by terminating the loop), but looks just
like any other assigment statement.  The 'goto' and label are at least
explicit about what is really going on.

(As a side comment, the test for the flag in the loop condition *will*
produce slower code on every C compiler I have ever used.  Few
compilers for any language do data flow analysis sophisticated enough
to detect that a variable is being used to cause a loop to terminate,
replace assignments with branches, and *not* generate the test at the
top of the loop.  For time-critical inner loops, this can make a real
difference).

Error handling is another spot where goto's are often the lesser evil.
Take the code:

  some_func()
  {
    lock_the_lock(); open_the_faucet();

    while(...) {
      if ((buf = malloc(bufsize)) == NULL) goto error;
      if (readabuf(myfile, buf) == ERRORVALUE) goto error;
      ... process the buffer ...
      if (... the data was bogus ...) goto error;
      ... do some more ...
    }
    while (some_condition) prepare_the_report();
    print_the_report();
   error:
    close_the_faucet(); unlock_the_lock();
  }

There are two ways to eliminate the goto's that I'm aware of.  One is
to replace each "goto error" by

    { close_the_faucet(); unlock_the_lock(); return; }
   
If the function is ever changed to open the refrigerator as well, all
these sequences will have to be updated --- and ghod forbid one gets
missed!  The alternative is to replace each with:

    { errflag = true; break; }

and surround the report-making code with an "if (!errflag)".  This
adds a bogus variable and obscures intent of the code behind an
entirely gratuitous level of structure.  Besides, {{ insert entire
previous discussion of multi-level break }}.

Note that in both these cases, the underlying problem is that C lacks
a language feature (multi-level break; civilized error handling) and
the programmer is forced to fake it.  My claim is simply that faking
it with goto's is better, all around, than faking it with flags.  In
almost all cases, goto-free code is simpler, clearer, and often faster
and more compact.  *Almost* all.

Skip further argues that 

>    ... As programmers modify code with gotos, lack of understanding
>    of the entire structure of the program leads to local modifications.
>    Additional jumps to local labels, and additions of code that span
>    earlier structures not visible due to the goto-implementation
>    cause Entropy increase, and the code becomes unstructured.

I'm unconvinced.  If the maintainers of a program can't resist the
temptation to increase entropy, they'll screw it up, whether it
originally had goto's or not.  (Anyone charged with maintaining a
program, at any time, can --- get this --- *insert* goto statements
into code that had none of them to begin with!)  The sad fact is that
the *only* way to keep actively modified code from degenerating into
sludge is ...

>   ... I began examining
>   lots of other code and re-doing it without gotos. Sometimes this was
>   hard, and involved a total re-design of the code (see below).

... slash-and-burn maintenance.  If the original designer of the
program didn't think that *that* function would *ever* return an
error, or that the screen size would ever change in the *middle of a
run*, or, or, or ..., then the code has to be rethought and, often,
rewrit from scratch.  Patching around this kind of situation will
create a mess, but it's a worse mess if the code was unclear to begin
with.  And it *is an error* to mindlessly equate "clear" with
"goto-free". 

>   in EVERY case [of de-goto-izing] the code got more understandable,
>   more efficient, and shorter in both source and object form...

but only because

>   ... My removal of gotos sometimes required my return to the
>   functional specification of the system and a complete re-implementation.

Again, this is an argument for slash-and-burn maintenance, not an
argument against the goto statement.  (I do believe deeply in
slash-and-burn maintenance, but that's another story).

rst
rst@think.com
ihnp4!think!rst

My employer would be shocked ...

henry@utzoo.UUCP (Henry Spencer) (07/19/87)

> My point is that 99% of the time I see a goto in a C program, it is
> not there for any good reason...

The rule I follow is that the desire to use a goto is a symptom of poorly-
organized code, and in particular is a sign that code has not been split
up into functions as it should be.  Barring emergencies, the right response
is to step back a bit and consider whether the code needs reorganizing.
In twelve years of C programming, my experience has been that the answer
*invariably* is "yes".

I feel roughly the same way about "continue", by the way, although it's not
as bad and I do use it occasionally.

People who say "but I can't call functions, I can't afford the overhead"
usually have no idea where the time in their program really is going, and
thus have no rational basis for that statement.  There may indeed be a few
places where call overhead is unacceptable, but the time to do something
about that is *after* the program is working and can be profiled.  Then,
and only then, it *may* be appropriate to revise a few small pieces of the
code to be faster but a bit less clean.  Inverting the order of these steps
generally just makes an unnecessary mess.  Human intuition simply is not a
reliable guide to the location of the real bottlenecks.

See also Collyer&Spencer, "News Need Not Be Slow", Washington 1987 Usenix
conference proceedings, for more discussion of these issues in the context
of improving news performance by 1.5 orders of magnitude.
-- 
Support sustained spaceflight: fight |  Henry Spencer @ U of Toronto Zoology
the soi-disant "Planetary Society"!  | {allegra,ihnp4,decvax,utai}!utzoo!henry

henry@utzoo.UUCP (Henry Spencer) (07/19/87)

> What this use of the goto boils down to is an exceptional return.  
> C doesn't have any kind of exception handling mechanism, which is a
> part of any "complete set of structured constructs", so it is
> necessary to simulate exception handling using goto.

It is often possible, and usually more readable in my experience, to
simulate it using return.  This means splitting out the lump which
wants an "exception exit" into a separate function, and just using
return to punch out of it.  Retrofitting this into existing code is a
lot easier said than done, mind you -- the code has to be organized
with this approach in mind.

I am willing to concede that there may be programs which can't use this
approach without serious problems; I've just never written one.
-- 
Support sustained spaceflight: fight |  Henry Spencer @ U of Toronto Zoology
the soi-disant "Planetary Society"!  | {allegra,ihnp4,decvax,utai}!utzoo!henry

henry@utzoo.UUCP (Henry Spencer) (07/19/87)

> There is a nice class of decision trees which can NEVER be implemented smaller
> in a structure and and appear MESSIER when in a structure (to me anyway)
> versus just a couple labels and GOTOs to "help the structure out"...

Try putting it in a table-driven form before you reject goto-less solutions.
Usually still more readable, seldom significantly slower if done carefully.

Incidentally, I support a ten-year ban on use of the word "structured" to
mean anything other than "organized" (which is, remember, its original
meaning).  If you mentally make this substitution, it sheds a whole new
light on people who insist that "we can't use structured programming because
it's too inefficient/clumsy/hard/whatever".
-- 
Support sustained spaceflight: fight |  Henry Spencer @ U of Toronto Zoology
the soi-disant "Planetary Society"!  | {allegra,ihnp4,decvax,utai}!utzoo!henry

hymie@dvm.UUCP (Hyman Rosen) (07/19/87)

In article <3289@bigburd.PRC.Unisys.COM> weiss@bigburd.PRC.Unisys.COM (Tom Weiss) writes:
>
>Since now appears to be the time to express opinions about
>style/clarity, I would like to address my own pet peeve: the goto
>statement.
>
>There are very few legitimate uses for the goto statement, and C
>provides alternates for most of them.  ...
> ...
>Once I was involved in rewriting a piece of code which contained a ...
> ... goto [that] was used to jump
>forward into the middle of an if/else construct. ...

That's about the only time that I've had to use goto's. (I usually handle
jumping out of a couple of loops by an extra test.) The case that particularly
comes to mind is in converting a string to float, which I've had to do a
number of times (in situations where atof() or sscanf() were not options).
Handling the cases of no digits before the decimal point or no digits after
the decimal point always seems to require either a duplication of code, or
a branch into one of the cases of an if-else statement, and I always choose
the goto. On the other hand, another programmer I work with insists that this
is an abomination, and would outrightly ban jumps into blocks from C. Note
that in C++ such branches are forbidden when they would cause a declaration
of an item with a constructor to be bypassed.
-- 


								- Hymie

		...{decvax,ihnp4,ucbvax}!allegra!phri!orville!dvm!hymie

g-rh@cca.CCA.COM (Richard Harter) (07/19/87)

In article <322@dvm.UUCP> hymie@dvm.UUCP (Hyman Rosen) writes:
>> ... goto [that] was used to jump
>>forward into the middle of an if/else construct. ...
>
>That's about the only time that I've had to use goto's. (I usually handle
>jumping out of a couple of loops by an extra test.) The case that particularly
>comes to mind is in converting a string to float, which I've had to do a
>number of times (in situations where atof() or sscanf() were not options).
>Handling the cases of no digits before the decimal point or no digits after
>the decimal point always seems to require either a duplication of code, or
>a branch into one of the cases of an if-else statement, and I always choose
>the goto. On the other hand, another programmer I work with insists that this
>is an abomination, and would outrightly ban jumps into blocks from C. Note
>that in C++ such branches are forbidden when they would cause a declaration
>of an item with a constructor to be bypassed.

	Different folks, different strokes.  It's hard for me to think of
a way to code this particular problem where you have a conceivable reason
for wanting to jump into a if-else block.  It might be interesting if you
posted a sketch of the approach that occurs to you naturally.

	In theory I count myself among the defenders of the goto.  In
practice I use them very rarely if the language at hand has the constructs
I need.  For example in a 50,000 line PL/I program I used exactly one,
to transfer out of an on-condition block.  In a 50,000  line C program
I used six, all of which were used to do cleanup in error handling.
I avoid the need to escape from deep levels of nesting by never using
deep levels of nesting. 

	On the theoretical side, control constructs can be arranged
in a heirarchy of strengths:

0	if-then-else/while
1	forever loop
2	simple goto
3	procedure call/return
4	computed goto

Any program can be written using the level 0 constructs.

Any program can be written using the level 0 constructs.  Each level is
stronger than the one below it.  I.e. for any level we can find programs
which will be more expensive in use of resources (space, time) if the
constructs of that level are not used.

This is one reason why no-goto advocates often say that one should use
procedures to avoid code replication -- in effect, they are proposing
that one should replace the weaker construct (the goto) by a stronger
construct (the procedure call/return).  Unfortunately the procedure
call mechanism is not a panacea; the problems are (a) cost of invocation,
and (b) transfer of information to the called procedure.

Strikingly enough, the most powerful programming construct possible,
the computed goto, is available in C (and most alternative languages)
in the form of the switch/case construct.  In theory, and in practice,
problems with complex level 0 constructs can be resolved and simplified
by recasting them in the form of switch/case constructs.  I grant that
the switch/case construct can be just as obscure as the code it replaces.
Nonetheless it has been my experience that complicated logic problems
are most conveniently handled by thinking of the problem in terms of
a finite-state machine and a list of states and actions.
-- 

Richard Harter, SMDS Inc. [Disclaimers not permitted by company policy.]
			  [I set company policy.]

ron@topaz.rutgers.edu (Ron Natalie) (07/21/87)

> A large myth from the 70's, where structured programming was viewed
> as "no gotos", was that forward jumps out of loops were not structured.
> This is not true. A break transfers control to a known place and provides
> just as structured a piece of code as a while leaving the loop on a false
> condition.

No, it is the break or jump to varying levels of loop exit that causes
problems.  Generally a good test for structure is to make each executable
statement a point and draw lines indicating the possible paths from one
point to another point.  If the lines must cross, then you are losing
structure (in the "everything is deeply intertwingled" terminology of
DeMarco).

-Ron

ron@topaz.rutgers.edu (Ron Natalie) (07/21/87)

> The example everyone knows is multi-level break.  It's clearly
> structured, but C doesn't have it.

It is not clearly structured, it isn't structured at all.  It destroys
the loop structure.  See my previous message

> (It isn't even possible to use
> 'break' to get out of a singly nested loop if the body is a switch
> statment).

This is a bug in C.  "BREAK" was a bad choice, either switch should
have implicitly assume break before the next case or it should have
used a different reserve word.  Witness the difference in operation
of the word "continue" as a result.

-Ron

karl@haddock.ISC.COM (Karl Heuer) (07/21/87)

In article <7571@beta.UUCP> hwe@beta.UUCP (Skip Egdorf) writes:
>In any language that supports a complete set of structured constructs,
>there is NO NEED for a goto, and the statement should be removed from
>the language!

The statement is true with the qualifier.  However, I do not know any language
that supports what I would consider a "complete set" of structured constructs.
Perhaps ADA does, but I'm not sure I want to use something that big.

>Languages that do not have enough control structure should be used only
>with a pre-processor (e.g. Fortran and Ratfor).

Not always feasible.  Yes, if there's a Ratfor available I'll use it and avoid
the goto as much as possible.  But if I'm coding in C, it's unlikely that the
construct I need occurs so often that it's worthwhile to use a new language.

As for removing it from the language -- that has happened in the Bourne shell,
and it's a pain having to kludge around it.  (Still, it's better than the old
"goto" shell.)

For the record, I do not use goto very often.  When I do, it's usually for
error-handling (even then, I prefer "usage()" to "goto usage").  I've also
been known to implement coroutines using goto.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

flaps@utcsri.UUCP (07/22/87)

In article <6603@think.UUCP> rst@godot.think.com.UUCP (Robert Thau) writes:
>Error handling is another spot where goto's are often the lesser evil.
>Take the code:
>
>  some_func()
>  {
>    lock_the_lock(); open_the_faucet();
>
>    while(...) {
>      if ((buf = malloc(bufsize)) == NULL) goto error;
>      if (readabuf(myfile, buf) == ERRORVALUE) goto error;
>      ... process the buffer ...
>      if (... the data was bogus ...) goto error;
>      ... do some more ...
>    }
>    while (some_condition) prepare_the_report();
>    print_the_report();
>   error:
>    close_the_faucet(); unlock_the_lock();
>  }
>
>There are two ways to eliminate the goto's that I'm aware of.
[two not very appealing ways]

Here's the nice way to eliminate the gotos.  No extra charge for the
improved vertical spacing.  :-)

some_func()
{
    lock_the_lock();
    open_the_faucet();

    process_until_error();

    close_the_faucet();
    unlock_the_lock();
}


process_until_error()
{
    while(...) {
	if ((buf = malloc(bufsize)) == NULL)
	    return;
	if (readabuf(myfile, buf) == ERRORVALUE)
	    return;
	... process the buffer ...
	if (... the data was bogus ...)
	    return;
	... do some more ...
    }
    while (some_condition)
	prepare_the_report();
    print_the_report();
}

-- 

      //  Alan J Rosenthal
     //
 \\ //        flaps@csri.toronto.edu, {seismo!utai or utzoo}!utcsri!flaps,
  \//              flaps@toronto on csnet, flaps at utorgpu on bitnet.


"To be whole is to be part; true voyage is return."

mlinar@poisson.usc.edu (Mitch Mlinar) (07/22/87)

In article <8321@utzoo.UUCP> henry@utzoo.UUCP (Henry Spencer) writes:
>> There is a nice class of decision trees which can NEVER be implemented smaller
>> in a structure and and appear MESSIER when in a structure (to me anyway)
>> versus just a couple labels and GOTOs to "help the structure out"...
>
>Try putting it in a table-driven form before you reject goto-less solutions.
>Usually still more readable, seldom significantly slower if done carefully.
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
Yes, a table-driven form is goto-free, but I am not sure it is *really*
readable.  (I admit it is probably more readable than the goto solution.)

The main point I was trying to make (and supported by your statement),
is that the code is NOT always faster when done right.  Personally, I prefer
code that is maintainable, even if there is some speed loss.  (To say that
correct code is ALWAYS faster and/or smaller is a fallacy.)

-Mitch

dg@wrs.UUCP (David Goodenough) (07/22/87)

In article <765@haddock.ISC.COM> karl@haddock.ISC.COM (Karl Heuer) writes:
>In article <7571@beta.UUCP> hwe@beta.UUCP (Skip Egdorf) writes:
>>In any language that supports a complete set of structured constructs,
>>there is NO NEED for a goto, and the statement should be removed from
>>the language!
>
>The statement is true with the qualifier.  However, I do not know any language
>that supports what I would consider a "complete set" of structured constructs.
>Perhaps ADA does, but I'm not sure I want to use something that big.

Now it's my turn to play devil's advocate - I seem to remember that in
some obscure journal or other, one of those structured programming gurus
(i.e. Djykstra (sp??) / Wirth) said that the only structured concepts
needed are loops and ifs, everything else is just icing. Now looking at
every language so far designed, I see some form of loop and some form
of if. So what are we (myself included) all bitching about??????????
--
		dg@wrs.UUCP - David Goodenough

					+---+
					| +-+-+
					+-+-+ |
					  +---+

mwm@eris.BERKELEY.EDU (Mike (My watch has windows) Meyer) (07/23/87)

In article <8320@utzoo.UUCP> henry@utzoo.UUCP (Henry Spencer) writes:
<It is often possible, and usually more readable in my experience, to
<simulate it using return.  This means splitting out the lump which
<wants an "exception exit" into a separate function, and just using
<return to punch out of it.  Retrofitting this into existing code is a
<lot easier said than done, mind you -- the code has to be organized
<with this approach in mind.
<
<I am willing to concede that there may be programs which can't use this
<approach without serious problems; I've just never written one.

Depends on what you're willing to do to the function.

I just wrote a short utility (couple of hundred lines) that had as
many gotos as I've actually left in code in the last 10 years. In both
cases, I wrote the code without the goto, said "yuch", and rewrote it
with the obvious goto/label sets.

One case was just what you describe: needing a short-circuit exit from
a piece of code. The piece of code parsed a string, extracting six
integer values from it, and leaving the pointer to the string in a
specific location. I considered writing this as a function and using
the return for short-circuit, and got as far as writing (the compiler
in question support prototypes):

	char *parse_geometry(char *, int *, int *, int *, int *, int *, int *) ;

before deciding that this was going to be *ugly*. Wrapping those six
values up in a structure would have led to:

	six assignments to the members of geometry_data ;
	input_string = parse_geometry(input_string, &geometry_data) ;
	six assignments to extract the data from geometry_data ;

Not very much prettier.

If any of you who claim that there's *never* an excuse for a goto want
to look at this, and show me how to do it without goto's, I'd
appreciate it. I don't like gotos - I just couldn't see a more
readable way of doing things with this code. But be warned - it's not
a Unix utility.

	<mike
--
Must have walked those streets for hours,		Mike Meyer        
In the dark and in the cold,				mwm@berkeley.edu  
Before I really could accept,				ucbvax!mwm        
There's no place called hope road.			mwm@ucbjade.BITNET

mikec@tekred.TEK.COM (Mike Combs) (07/23/87)

In article <7571@beta.UUCP> you write:
]In article <3289@bigburd.PRC.Unisys.COM>, weiss@bigburd.PRC.Unisys.COM (Tom Weiss) writes:
]> Since C provides the break statement to break out of a loop, the
]> continue statement to jump back to the top of a loop, the return
]> statement to immediately exit a function, and access to system calls
]> (e.g. exit) that can terminate execution in error handling functions,
]> there are few 'legitimate' uses for goto.
]
]In any language that supports a complete set of structured constructs,
]there is NO NEED for a goto, and the statement should be removed from
]the language!
]Languages that do not have enough control structure should be used only
]with a pre-processor (e.g. Fortran and Ratfor).
]
]					Skip Egdorf
]					hwe@lanl.gov

What would you say a "complete set of structured constructs" includes?
Does Pascal have a complete set?

I'm a longtime Pascal programmer, and just starting to learn C.
Pascal does not have the break, continue, or return statements.
In your opinion, in the cases Weiss refers to, does this justify use of goto?
-- 
Mike A. Combs
     ^--The "A" is for: "Almost finished debugging."
GEnie: mike.combs   MCI: mcombs   tektronix!tekgen!tekred!mikec
terrorist, contras, drugs, Iran, secret, NSA, CIA <- NSA line-eater food :-(
-- 
Mike A. Combs
     ^--The "A" is for: "Almost finished debugging."
GEnie: mike.combs   MCI: mcombs   tektronix!tekgen!tekred!mikec
terrorist, contras, drugs, Iran, secret, NSA, CIA <- NSA line-eater food :-(

aglew@ccvaxa.UUCP (07/23/87)

Here's a question of taste:

	When you've completed an application nicely in C,
	using functions everywhere, and it's still too slow,
	which would you rather do?:

	(1) Rewrite parts of it in assembler,

     	or (2) Use gotos?

jfh@killer.UUCP (The Beach Bum) (07/23/87)

In article <3567@oberon.USC.EDU>, mlinar@poisson.usc.edu (Mitch Mlinar) writes:
> In article <8321@utzoo.UUCP> henry@utzoo.UUCP (Henry Spencer) writes:
> >> There is a nice class of decision trees which can NEVER be implemented smaller
> >> in a structure and and appear MESSIER when in a structure (to me anyway)
> >> versus just a couple labels and GOTOs to "help the structure out"...
> >
> >Try putting it in a table-driven form before you reject goto-less solutions.
> >Usually still more readable, seldom significantly slower if done carefully.
>                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
> Yes, a table-driven form is goto-free, but I am not sure it is *really*
> readable.  (I admit it is probably more readable than the goto solution.)
> 
> The main point I was trying to make (and supported by your statement),
> is that the code is NOT always faster when done right.  Personally, I prefer
> code that is maintainable, even if there is some speed loss.  (To say that
> correct code is ALWAYS faster and/or smaller is a fallacy.)
> 
> -Mitch

I find when writing programs as finite state machines, that the code is
somewhat less readable _but_ almost always infinitely more correct.
Usually some big switch statement and a table of state changes (anyone
who has written a push down automaton knows just how big these tables can
get for a grammar like C or pascal ...) does the trick.  The actual code
is so simple and the tables can be generated almost automatically (unless
you use yacc, in which case it can be generated automatically :-)

That, in this humble programmer's opinion, is the highest form of structure.
A couple dozen lines of code, and an array with a couple thousand entries ...

The points I am trying to make are:

	1). Readablity affects maintainablity.
	2). Structure affects maintainablity.
	3). Design affects maintainablity.

I _always_ document my goto's (about 1 or 2 percent of my statements)
with a `come from' that describes the state and condition of the program
when execution reaches that point in the code.  This does two things:

	1). Improves the readablity.
	2). (generally) Improves the design.

The second is a result of having to think of what conditions you want
flow control to reach the goto.  Consider the following fragment:
(Keep in mind that I would never actually write this piece of code ...)

	OpenFile (FileName, FilePointer, FileBuffer, RecordSize)
	char	*FileName;
	FILE	**FilePointer;
	char	**FileBuffer;
	int	RecordSize;
	{
		*FilePointer = NULL;
		*FileBuffer = NULL;

		if (access (FileName, 0) == -1)
			goto ErrorExit;

		if ((*FilePointer = fopen (FileName, "r")) == NULL)
			goto ErrorExit;

		if ((*FileBuffer = malloc (RecordSize)) == NULL)
			goto ErrorExit;

	/* Maybe some more processing, and jumps to ErrorExit */
		return (1);

	/* ErrorExit - handle all known forms of errors ...
	 * 	You know how you got here? Right?  You know what to do? Right?
	 */

	ErrorExit:
		if (*FilePointer)
			fclose (*FilePointer);

		if (*FileBuffer)
			fclose (*FileBuffer);

		return (0);
	}

Any questions?  This may not be `structured', ala University Pascal style
structured, but I'd rather see this than some nasty collection of deeply
nested if-then-else-if-...'s or 3 or 4 `error handlers' that look just
like the code in ErrorExit with a few minor changes.

- John.
-- 
John F. Haugh II		HECI Exploration Co. Inc.
UUCP:	...!ihnp4!killer!jfh	11910 Greenville Ave, Suite 600
"Don't Have an Oil Well?"	Dallas, TX. 75243
" ... Then Buy One!"		(214) 231-0993

dave@sdeggo.UUCP (David L. Smith) (07/23/87)

In article <264@wrs.UUCP>, dg@wrs.UUCP (David Goodenough) writes:
- Now it's my turn to play devil's advocate - I seem to remember that in
- some obscure journal or other, one of those structured programming gurus
- (i.e. Djykstra (sp??) / Wirth) said that the only structured concepts
- needed are loops and ifs, everything else is just icing. Now looking at
- every language so far designed, I see some form of loop and some form
- of if. So what are we (myself included) all bitching about??????????
- --
- 		dg@wrs.UUCP - David Goodenough

All you need to travel across the United States is yor bare feet but it's
a whole lot nicer in a plane :-)




-- 
David L. Smith
{sdcsvax!sdamos,ihnp4!jack!man, hp-sdd!crash}!sdeggo!dave
sdeggo!dave@sdamos.ucsd.edu 
Microport Unix!  More bugs for the buck!

gwyn@brl-smoke.ARPA (Doug Gwyn ) (07/24/87)

In article <264@wrs.UUCP> dg@wrs.UUCP (David Goodenough) writes:
>I seem to remember that in
>some obscure journal or other, one of those structured programming gurus
>(i.e. Djykstra (sp??) / Wirth) said that the only structured concepts
>needed are loops and ifs, everything else is just icing.

That's not quite what the Bohm-Jacopini theorem says.  It says that
any procedural logic (flowchart) can be derived from combinations of
three basic elements: sequence, if-then-else, and do-while.

But that does not have as much relevance to the discussion as you
might think.  Consider that propositional calculus (Boolean logic)
needs only one operator (your choice of NAND or NOR); nevertheless
it is much more in line with human modes of thinking (at least in
the civilized Western world) to express such logic in terms of
several different operators (AND, OR, NOT, IMPLIES, ...).  This is
not "incorrect", and from a practical point of view it is MORE
correct than insisting on writing all Boolean operations in terms
of NANDs.  Similarly, just because one CAN write a program using
a tiny number of constructs does not at all mean that one SHOULD
do so.  It is more important that the program be patently correct
(i.e., that it exactly implement the design function) and that it
be susceptible to ready understanding and modification without
losing those nice properties.

Discussion about whether or not to use "goto" is just about as
pointless as discussing whether or not to call a variable, "event";
if it makes sense to do so in the context of producing correct,
maintainable code, one will naturally do so without having to stop
to debate the issue.  I don't often use "goto" in my C code, but
there are times when it is simply the most obviously correct way
to implement a procedure.  One COULD avoid using "goto" but why
unnecessarily convolute the code?

Now, I'm sure we've all seen horrendous abuses of "goto".  But ALL
programming constructs can be and have been badly abused.  I recall
one posted use of "switch" that was admirably ingenious and gruesome!
(Sorry, I don't recall the details.)

cik@l.cc.purdue.edu (Herman Rubin) (07/24/87)

I have actual subroutines which, inside the main loop, have code such as

	.....
mod:	.....
	.....
	if(....)goto terma;
	....
	if(...)goto termb;
	...
	if(......)goto termc;
h:	....
	if(.....)goto terma;
	....
	goto h;
terma:	......;
	goto mod;
termb;  ....;
	goto merge;
termc;	....;
merge:	....; goto finish;
termd:  ....;
finish: ....;}

as well as other goto's internally in the code.  The goto h could be replaced
by a while() statement, but would be no more readable.  I see no remotely
reasonable way to replace the other goto's without both slowing the code and
decreasing readability.

	I know goto's can be dangerous, but I do not call a tank to drive
me to work.  As far as proving the correctness of a program, this program is
actually fairly short, and each part is implementing a case in a rather
intricate procedure which does a lot of branching from case to case until
a termination condition is attained.  If the C compiler on the VAX could be
persuaded to use all the registers, no non-explicit memory references would
be used.  Clarity of code is not achieved by not allowing the programmer to
do what is natural, and there is nothing unnatural about goto's except in the
minds of the ignorant or totalitarian :-).
-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu or pur-ee!stat-l!cik or hrubin@purccvm.bitnet

lmiller@venera.isi.edu (Larry Miller) (07/24/87)

In article <264@wrs.UUCP> dg@wrs.UUCP (David Goodenough) writes:
>>Perhaps ADA does, but I'm not sure I want to use something that big.
>
>Now it's my turn to play devil's advocate - I seem to remember that in
>some obscure journal or other, one of those structured programming gurus
>(i.e. Djykstra (sp??) / Wirth) said that the only structured concepts
>needed are loops and ifs, everything else is just icing. Now looking at
>every language so far designed, I see some form of loop and some form
>of if. So what are we (myself included) all bitching about??????????
>--

The paper was (refer format):

%A C. Boehm
%A G Jacopini
%T Flow Diagrams, Turing Machines, and Languages
With Only Two Formation Rules
%J C. ACM
%D May, 1966

grazier@fmsrl7.UUCP (Kevin Grazier) (07/24/87)

In article <7571@beta.UUCP> hwe@beta.UUCP (Skip Egdorf) writes:
>In any language that supports a complete set of structured constructs,
>there is NO NEED for a goto, and the statement should be removed from
>the language!

For what it's worth, I don't entirely agree.   Take, for instance, code
which is time-critical (control systems software, for example).  Now, 
add nested switch statements.  When the code is executed at the "lowest
level" of the switch, it's so much more practical to jump to the end
of the swithces instead of executing the break break break.......ad infinitum 
sequence.  When you're running real-time code which is running something like
an engine, you look for speed ANYWHERE.  This is another case in which
practicality diverges slightly from the theoretical.

On a more intangible level, I seem to remember being taught as an undergrad
that there are still a COUPLE (and I mean just that) algorithms that
can't be done without a goto.  Unfortunately, I can't remember what they
did, though.  If this receives too many flames, maybe I'll have to look
it up.  What the instructor was trying to show by this example, though, was
that there are, indeed, only a COUPLE algorithms which cannot be done
without gotos and that since we weren't doing anything near as complex,
we shouldn't use them (actually couldn't use would be more proper because
if you used one, you flunked the assignment).










-- 
Kevin R. Grazier                                Have you driven a Ford, lately?
Ford Motor Company Scientific Research Labs
Advanced Powertrain Systems & Controls Engineering
uucp: {philabs | pyramid} !fmsrl7!grazier OR  grazier@fmsrl7.UUCP
VOICE: (313) 739-8586  

asg@pyuxf.UUCP (alan geller) (07/24/87)

In article <1237@ius2.cs.cmu.edu>, edw@ius2.cs.cmu.edu.UUCP writes:
> 
> In an article by Skip Egdorf (hwe@beta.UUCP), Skip sez,
> > There are NO legitimate uses for the goto statement...
> 
>    I sez..
>    There is a whole class of problems that map very nicely into goto contructs.
> They are simulation of NFAs and DFAs (ie finite state machines).
> 
>    States map very nicely to labels and transitions map very nicely into
> if (input == ?) goto label.
> 
>    The most readable way one can represent the NFA/DFA is through a mesh
> of gotos with a diagram of the machine in comments :-).

I disagree -- the most readable way to present a finite state machine
is with a transition matrix (array), an action matrix (array), and a
driver routine that looks like:

		state = INITIAL_STATE;
		while (state != ACCEPT_STATE) {
			input = getInput();
			performAction(actionMatrix[state][input]);
			state = transitionMatrix[state][input];
		}
or something along those lines.  This produces code that is more easily
maintained, more compact, and often faster than using a bushel of goto's.

Alan Geller		{rutgers,princeton}!pyuxp!pyuxf!asg
Bellcore, 33 Knightsbridge Rd., Piscataway, N.J.  (201)-699-7641
My employers had nothing to do with the above -- unless it's patentable :-).

rwhite@nu3b2.UUCP (Robert C. White Jr.) (07/25/87)

In all your goto stuff I find that yhat you really want is the
setjump() longjump() construct whic has been in all [both might
be a better word, its been marginaly over three] the compilers 
I have had to work with.  It would seem to address all your examples
of necessary goto(s).

You call setjump() and get a return code indicating the jump has been
set to that point.  If you later call longjump() execution skips BACK
to the setjump() call but this time it exits with a diferent value you
can test.  This only works backwards as it mostly saves the stack frame
in some global position. but it will preform a multi level "break" as
long as you are on the same or lower execution branch as the setjump()
call.
	The conditional structure seems valid enough, and as it is really
a controlled, down-only, step is seems a terrific structual behavor for
a language which is basicly a "portable asssembeler" [as some have called
it]  It is exxentially the same as a multi-level break, but it requires
the structual planning to be done at the broken-to, instead of broken-
from, level.  by this means, extra levels [functions/loops/falderall]
can be inserted in the execution tree without having to find every
"break 4" and change it to a "break 5" [etc], the programmer must plan
a structured response to every possible goto.


Robert.

Disclaimer:  My mind is so fragmented by random excursions into a
	wilderness of abstractions and incipient ideas that the
	practical purposes of the moment are often submerged in
	my consciousness and I don't know what I'm doing.
		[my employers certainly have no idea]

gwyn@brl-smoke.ARPA (Doug Gwyn ) (07/25/87)

In article <556@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
-	.....
-mod:	.....
-	.....
-	if(....)goto terma;
-	....
-	if(...)goto termb;
-	...
-	if(......)goto termc;
-h:	....
-	if(.....)goto terma;
-	....
-	goto h;
-terma:	......;
-	goto mod;
-termb;  ....;
-	goto merge;
-termc;	....;
-merge:	....; goto finish;
-termd:  ....;
-finish: ....;}
-as well as other goto's internally in the code.

That's an example of the sort of thing that gave GOTO a bad name.
If you draw connecting paths between the gotos and their targets,
you get the infamous "spaghetti".  It is always POSSIBLE that such
code is correct, but it is not patent from its structure.  Indeed,
it's not even clear that the branching necessarily terminates, and
the termination condition if written out would be exceedingly
complex.  By the way, how is label "termd" reached?  Are you sure
this code is correct?  Would you be comfortable making serious
revisions to it a few years from now?  I really can't recommend
this style of coding.

gwyn@brl-smoke.ARPA (Doug Gwyn ) (07/26/87)

In article <1125@nu3b2.UUCP> rwhite@nu3b2.UUCP (Robert C. White Jr.) writes:
>In all your goto stuff I find that yhat you really want is the
>setjump() longjump() construct...

NO!  longjmp() is for emergency use only; it suffers from several
problems:

	(1)  It's a non-local goto, which is even worse than a local
	goto from the standpoint of style.  It is also more complex
	because of the implied conditional test.

	(2)  setjmp()/longjmp() have to save and restore considerable
	context and usually involve run-time library function calls,
	so it is much less efficient than goto.

	(3)  It is sometimes very hard to implement setjmp()/longjmp()
	in such a way that something doesn't get messed up at run
	time, usually by reentrancy from a signal handler or at least
	corruption of register variables.

I don't recommend setjmp()/longjmp() at all, but if you need to leap
out from the middle of deeply nested function invocations to the
"top" of a master control loop, they are useful for that.  Beware of
longjmp() from a signal handler, though; no telling what corruption
of data structures that may cause.

cik@l.cc.purdue.edu (Herman Rubin) (07/26/87)

In article <6172@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn ) writes:
> In article <556@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:

[details omitted]

> That's an example of the sort of thing that gave GOTO a bad name.
> If you draw connecting paths between the gotos and their targets,
> you get the infamous "spaghetti".  It is always POSSIBLE that such
> code is correct, but it is not patent from its structure.  Indeed,
> it's not even clear that the branching necessarily terminates, and
> the termination condition if written out would be exceedingly
> complex.  By the way, how is label "termd" reached?  Are you sure
> this code is correct?  Would you be comfortable making serious
> revisions to it a few years from now?  I really can't recommend
> this style of coding.

First, I gave only a disjointed fragment of the code, not enough to produce
the flow.  Second, there is random input at all stages of the code before
reaching a terminating condition, and I can only state that the code terminates
with probability one, but the expected termination time is short.  Third, I
doubt that I would be able to prove the correctness of the algorithm without
knowing what the purpose of each section is; however, knowing this, it is not
difficult.  The procedure is a modification of a more easily described
algorithm, but using the minimum amount of random information to carry 
out each stage--only isolated random bits are used.  Fourth, it would be
folly to attempt to revise this code without that description.  If you think
you can produce better code with or without the use of goto's, please let me
know and I will give you the opportunity, but note that by better I mean
faster.

-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu or pur-ee!stat-l!cik or hrubin@purccvm.bitnet

ebh@cord.UUCP (Ed Horch) (07/26/87)

In an article by Skip Egdorf (hwe@beta.UUCP), Skip sez,
> There are NO legitimate uses for the goto statement...

What about the K&R example

	if( disaster )
		goto bailout;

-Ed

jfh@killer.UUCP (The Beach Bum) (07/26/87)

In article <264@wrs.UUCP>, dg@wrs.UUCP (David Goodenough) writes:
> In article <765@haddock.ISC.COM> karl@haddock.ISC.COM (Karl Heuer) writes:
> >In article <7571@beta.UUCP> hwe@beta.UUCP (Skip Egdorf) writes:
> >>In any language that supports a complete set of structured constructs,
> >>there is NO NEED for a goto, and the statement should be removed from
> >>the language!
> >
> >The statement is true with the qualifier.  However, I do not know any language
> >that supports what I would consider a "complete set" of structured constructs.
> >Perhaps ADA does, but I'm not sure I want to use something that big.
> 
> Now it's my turn to play devil's advocate - I seem to remember that in
> some obscure journal or other, one of those structured programming gurus
> (i.e. Djykstra (sp??) / Wirth) said that the only structured concepts
> needed are loops and ifs, everything else is just icing. Now looking at
> every language so far designed, I see some form of loop and some form
> of if. So what are we (myself included) all bitching about??????????

Every high level construct can be faked with just if's and goto's.

But even if's can be faked with top-tested loops.  (while loops in
c and pascal, etc)

Consider:

	if boolean_expression then
		statement;

and

	loop_ending_flag := false;
	while boolean_express and not loop_ending_flag do begin
		statement;
		loop_ending_flag := true
	end

both of these are the same!  Only the second _probably_ runs slower
and definitely looks like crap.

The second example is for wanting a loop and no goto's:

	while_loop:
	if boolean_expression then begin
		statement;
		goto while_loop
	end;

and
	while boolean_expression do
		statement;

Once again, both of these should be the same, except the second is
now much more clear.  Even a case for the case statement can be
made with multi-level if's or some other form of computed goto.
The variety of language contructs in a language such as pascal or
c makes for _more_clearly_ expressing the intent of the programmer.
I am against any group of people telling me not to use a language
construct.

- john.
-- 
John F. Haugh II		HECI Exploration Co. Inc.
UUCP:	...!ihnp4!killer!jfh	11910 Greenville Ave, Suite 600
"Don't Have an Oil Well?"	Dallas, TX. 75243
" ... Then Buy One!"		(214) 231-0993

edw@ius1.cs.cmu.edu (Eddie Wyatt) (07/27/87)

In article <960@fmsrl7.UUCP>, grazier@fmsrl7.UUCP (Kevin Grazier) writes:
> sequence.  When you're running real-time code which is running something like
> an engine, you look for speed ANYWHERE.  This is another case in which
> practicality diverges slightly from the theoretical.

    Buy yourself one hell of an optimizing compiler or write it in assembly
if your code is that time critial.

> 
> On a more intangible level, I seem to remember being taught as an undergrad
> that there are still a COUPLE (and I mean just that) algorithms that
> can't be done without a goto.  Unfortunately, I can't remember what they
> did, though.  If this receives too many flames, maybe I'll have to look
> it up.  What the instructor was trying to show by this example, though, was
> that there are, indeed, only a COUPLE algorithms which cannot be done
> without gotos and that since we weren't doing anything near as complex,
> we shouldn't use them (actually couldn't use would be more proper because
> if you used one, you flunked the assignment).
> 

   Sorry, but ALL computable problems can be coded with ONLY while statements
and if-then-elses for flow of control.  In fact I'll go one step farther, ALL
computable problems can be coded with only ONE while statement and
if-then-elses.  Every Von Newman machine is an example of this.

	while (1)
      	    fetch instructure	     /* can be viewed as an array index */
	    decode instructure	     /* can be decoded with only if-then-else
					think about */
	    execute instruction      /* goto statements are actually just
				        set PC = label */
	    inc PC

   I sugguest you pick up a book on Automata Theory and formal languages. 
The actually theorem that states if gotos are over kill was derived in
the 30's by Kleene.  I also sugguest you look up Church-Turning Thesis.

-- 

					Eddie Wyatt

e-mail: edw@ius1.cs.cmu.edu

edw@ius1.cs.cmu.edu (Eddie Wyatt) (07/27/87)

In article <162@pyuxf.UUCP>, asg@pyuxf.UUCP (alan geller) writes:
> In article <1237@ius2.cs.cmu.edu>, edw@ius2.cs.cmu.edu.UUCP writes:
> > 
> > In an article by Skip Egdorf (hwe@beta.UUCP), Skip sez,
> > > There are NO legitimate uses for the goto statement...
> > 
> >    I sez..
> >    There is a whole class of problems that map very nicely into goto contructs.
> > They are simulation of NFAs and DFAs (ie finite state machines).
> > 
> >    States map very nicely to labels and transitions map very nicely into
> > if (input == ?) goto label.
> > 
> >    The most readable way one can represent the NFA/DFA is through a mesh
> > of gotos with a diagram of the machine in comments :-).
> 
> I disagree -- the most readable way to present a finite state machine
> is with a transition matrix (array), an action matrix (array), and a
> driver routine that looks like:
> 
> 		state = INITIAL_STATE;
> 		while (state != ACCEPT_STATE) {
> 			input = getInput();
> 			performAction(actionMatrix[state][input]);
> 			state = transitionMatrix[state][input];
> 		}
> or something along those lines.  This produces code that is more easily
> maintained, more compact, and often faster than using a bushel of goto's.

	    START : 
	        input = getchar();
		if (isdigit(input) goto INTEGER;
		if (input == '.')  goto FLOAT ;
		if (input == '+')  goto START ;
		if (input == '-')  goto START ;
		goto ERROR;

	    INTEGER :
	        input = getchar();
		if (isdigit(input) goto INTEGER;
		if (input == '.')  goto FLOAT2;
		ungetc(stdin,input);
		return(INT_TOKEN);

	    FLOAT :
	        input = getchar();
		if (isdigit(input) goto FLOAT2;
		goto ERROR;

	    FLOAT2 :
	        input = getchar();
		if (isdigit(input) goto FLOAT2;
		ungetc(stdin,input);
		return(FLOAT_TOKEN);

	    ERROR :
		(void) fprintf(stderr,"lex error\n");
		goto START; /* try again */

     Is the above code really that hard to understand?  BTW I know
there are much more efficient ways of coding the above - this is just
an example.

     I would say that transitional tables are no more readable than this
approach, but I guess this is all a matter of taste.

   Also, the transitional tables have one very good advance over this approach
which is, it requires the programmer to enumerate all posible actions
associated with every state-input pair.  But transitional tables are
wasteful if the matrix is sparse (ie. more error transitions than good
transitions).

-- 

					Eddie Wyatt

e-mail: edw@ius1.cs.cmu.eduo

edw@ius1.cs.cmu.edu (Eddie Wyatt) (07/28/87)

  As someone kindly pointed out 
		read(fileno(stdout),&c,sizeof(char))
should have been
		read(fileno(stdin),&c,sizeof(char))
			       ^^

-- 

					Eddie Wyatt

e-mail: edw@ius1.cs.cmu.edu

schwartz@swatsun (Scott Schwartz) (07/29/87)

In article <28700017@ccvaxa>, aglew@ccvaxa.UUCP writes:
+-------
| 	When you've completed an application nicely in C,
| 	using functions everywhere, and it's still too slow,
| 	which would you rather do?:
| 
| 	(1) Rewrite parts of it in assembler,
|      	or (2) Use gotos?
+-------

I would profile it and rewrite parts in assembler.  

We've all heard that line before, so no one should be surprised that it
turns out to be the case.  I can't think of any sizable program that would
exibit a _dramatic_ speed increase when you ripped out switches and 
if-then-else's to put in goto's.  The only case where this seems to be
any kind of issue is in state machines and parsers;  there has been enough
discussion both ways on this recently to convince me that goto's are not
necessarily the best way to do it in every case.  

I happen to like the "ErrorExit" usage that was talked about in several
prevous postings, but I disagree with the insinuation above that functions
are too slow to be practical.  Two experiences come to mind:  The first
case was an egrep style program I once wrote, the second was a ray tracing
program a friend of mine wrote.  In both cases I wanted to speed things up
without doing rewrites in assembler.  So I tried replacing some of the
functions in the inner loops with inline expansions [naturally a good
optimizing compiler would have done that for me, but...].  The functions I 
chose to replace were identified (using unix profiling tools) and were
called over 300,000 times in the test run.  Replacing with inline code
made virtually no difference in execution time.  What I concluded from
this exercise was that quick fixes usually don't work, and that in many cases
function calls are less expensive than you think, especially if you 
have a naive compiler.

-- 
# Scott Schwartz 
# ...{{seismo,ihnp4}!bpa,cbmvax!vu-vlsi,sun!liberty}!swatsun!schwartz

rwhite@nu3b2.UUCP (Robert C. White Jr.) (07/29/87)

In article <1191@killer.UUCP>, jfh@killer.UUCP (The Beach Bum) writes:
> 
> Every high level construct can be faked with just if's and goto's.
	[Lots of examples of end-tested loops and such]
> 

	The whole point is not that people should "fake" high level
constructs with goto(s) and if(s).  If you think a moment, you will
realize that vary few [any?] computers have a machine level "while"
construct that can span multiple instructions.  When push comes to
shove ALL high leve constructs are reduced to tests and branches
(if(s) and goto(s))  But it is silly bordering on foolish to maintain
that using if and goto to build a loop will net more efficient code.
	Optimizing compilers can only optimize if they can group
code statments and analize the possible execution paths.  By spotting
obviously (needlessley) repetitive code and moving it outside the/a
loop in question:

i.e.
int	func(x);
int	*x;
{
.
.
.
	while (test-which-does-not-use-x-as-value) {
		y = x+4;
		x+4 = z;
		[loop-body-which-does-not-modify-x]
		}
.
.
.
}

	In this example the x+4 would be moved out of the loop to
increase efficency.  If I did this loop with gotos, the compiler
would not know where "out of the loop" was, so the calculation would
be kept in every instance.  Also an if thends to generate:
test
jump forward on false to X
true instructions
jump forward towards exit to Y
label X
false instructions
label Y

If you seround this with the loop branching, and the add the branch out
as the "true instructions" for a negated test [just ignore the "else"
branch sequence] you end up branching twice for each condition.  the
extra branch instructions will flush any instruction prefech queus and
generally slow the system down an extra time.

	Between the extra branching and the loss of optomizing the code
generated by goto programming is almost always slower than the loops.
inline testing for a nonzero value [C boolean tests] are usually 
inline zero-extra-branch tests which can slip into the stream in such a
way that no prefetch queues are disrupted and no extra branches take
place.  To use test-break logic you must branch excessively around
the false contidtions.

on an 80x86 machine or 80x88 machine a bolean test is:
mov ax,0
test ax,[address of value]
je instruction-after-loop  ; /* jump if equal, out of loop

As long as the boolean is true, the jump is ignored.  After optomizing
multiple tests, only the last two are repeated.  This is VERY efficent
code.  if you use the test and break form the end I garentee at least one
executed branch per test.

Claiming a boolean test in a while loop's conditional expression
will slow code is stupid.  Get you your DDT [Dynamic Debugging Tool]
of choice and examine the code.

Using GOTO is a BOG.

Robert.

[I know I can't spell, if you don't like my words, but all you answer
is the spelling it goes to >/dev/null, ALL other critiques taken
seriously.]

nu3b2!rwhite

mike@arizona.edu (Mike Coffin) (07/30/87)

In article <1129@nu3b2.UUCP> rwhite@nu3b2.UUCP (Robert C. White Jr.) writes:
> ...
>	Optimizing compilers can only optimize if they can group
>code statments and analize the possible execution paths.  By spotting
>obviously (needlessley) repetitive code and moving it outside the/a
>loop in question:

	[ example containing a while loop omitted ]

>
>	In this example the x+4 would be moved out of the loop to
>increase efficency.  If I did this loop with gotos, the compiler
>would not know where "out of the loop" was, so the calculation would
>be kept in every instance.  ...

This is incorrect.  It is not at all difficult for a compiler to
detect loops that are built from gotos instead of higher level
constructs.  Any decent compiler book has algorithms for doing it. In
fact, most optimizing compilers convert source code into some
intermediate form before reorganizing it; in the process of converting
to intermediate code the higher-level constructs (with the exception
of switch/case-like statements) are turned into ifs and gotos.

If you want to argue against gotos, I think you'll have to do it on
the basis of readability.

	mike coffin
	(mike@arizona.edu)

rcw@qetzal.UUCP (sysop) (08/02/87)

In article <1125@nu3b2.UUCP>, rwhite@nu3b2.UUCP (Robert C. White Jr.) writes:
[The Robert C. White, Jr. quoted is not me. I am the other one]
> 
> In all your goto stuff I find that what you really want is the
> setjump() longjump() construct which has been in all [both might
> be a better word, its been marginally over three] the compilers 
> I have had to work with.  It would seem to address all your examples
> of necessary goto(s).
> 

I agree! We have used setjump() and longjump() to develop an 
error system for software development in-house. This allows us

	1. To set an error control point.
	2. To Remove an error control point.
	3. Return to previous error control point.
	4. Handle cleanup.
	5. Eliminate a lot of code like:

	   if (status == BARF) barfflag++;

	This sort of code usually constitutes > 1/3 the
        project.

	6. Allow error logging in a journal.

We have created quite a few utility routines which eliminate the
need for the programmer to constantly check status. For example,
we have a routine U_open, which is an interface to open().

	fd = U_open("Foo",O_RDWR,0666);

The U_open routine issues the appropriate message to the user's 
terminal if there is a problem. You don't have to check errno or fd
yourself, just open it and away you go. 

Unfortunately, our code is proprietary, but I can hitch you up with 
an excellent consultant who can provide an excellent error system for 
you. 
-- 
Robert C. White, Jr. Graphics Information, Inc.   ****************
UUCP: ihnp4!upba!qetzal!rcw isis!qetzal!rcw       * OIL/GAS/LAND *
USPS: 3067 Robin Way, Denver, CO 80222            *  CARTOGRAPHY *
ATT : +1 303 759-3666                             ****************

henry@utzoo.UUCP (Henry Spencer) (08/03/87)

> 	When you've completed an application nicely in C,
> 	using functions everywhere, and it's still too slow,
> 	which would you rather do?:
> 
> 	(1) Rewrite parts of it in assembler,
> 
>      	or (2) Use gotos?

Neither.  First, you *profile* it, to find out where the time is really
going; human guessing (even if dignified by names like "intuition" or
"professional judgement") is usually wrong.  Then, you revise the code
in the hot spots to use better algorithms.  If you are really greasing
the code hard, it may be necessary to merge previously-separate functions
into their callers, to reduce call overhead.  The big wins come from
reorganization to avoid work entirely, not from twiddling to do the work
a little bit faster.

For example, C News is now 1.5 orders of magnitude faster than B News,
and will probably be still faster when Geoff and I release it, even though
it contains no gotos and no assembler.  We both dislike gotos, and avoid
assembler on the grounds that it's unnecessary and a maintenance nightmare
for portable code.  (There ARE occasions when small assembler functions can
be a win, if you are trying to perform operations that C isn't too good at,
but often a radically new algorithm -- in C -- is still faster.)  Geoff
does a lot of profiling and code analysis and rewriting (I do some too, but
his parts of the code are the hardest and most speed-critical ones), and we
both think a lot about ways to avoid overhead.  For the gory details, see
our paper in the Winter 1987 Usenix proceedings.  We may do a followup
paper someday about all the things we've thought of since.
-- 
Support sustained spaceflight: fight |  Henry Spencer @ U of Toronto Zoology
the soi-disant "Planetary Society"!  | {allegra,ihnp4,decvax,utai}!utzoo!henry

henry@utzoo.UUCP (Henry Spencer) (08/03/87)

> Also, the transitional tables have one very good advance over this approach
> which is, it requires the programmer to enumerate all posible actions
> associated with every state-input pair...

I'd like to second this comment; I had a recent experience with such a
situation.  That code would *never* have been right if I hadn't converted
it to a table-driven approach, which forced an organized, careful analysis
of each and every case rather than "add code until it seems to work".
-- 
Support sustained spaceflight: fight |  Henry Spencer @ U of Toronto Zoology
the soi-disant "Planetary Society"!  | {allegra,ihnp4,decvax,utai}!utzoo!henry

peter@sugar.UUCP (Peter da Silva) (08/04/87)

Was that posting just a fragment of your imagination? You're actually
suggesting that you replace a non-structured construct with one that is
no better structured, requires more work on the part of the programmer,
and executes slower?

I though I heard you suggesting that:

	if(...) {
		while(...) {
			for(...) {
				....
				goto loopexit;
			}
		}
	}
loopexit:

be replaced by:

	struct jmp_buf loopexit;

	if(!setjmp(&jmp_buf)) {
		if(...) {
			while(...) {
				for(...) {
					....
					longjmp(&jmp_buf, 1);
				}
			}
		}
	}
-- 
-- Peter da Silva `-_-' ...!seismo!soma!uhnix1!sugar!peter (I said, NO PHOTOS!)

roger@esquire.UUCP (Roger Reid) (08/04/87)

In article <28700017@ccvaxa> aglew@ccvaxa.UUCP writes:
>
>Here's a question of taste:
>
>	When you've completed an application nicely in C,
>	using functions everywhere, and it's still too slow,
>	which would you rather do?:
>
>	(1) Rewrite parts of it in assembler,
>
>     	or (2) Use gotos?



I'd rather find a  better algorithm than  pick up a nanosecond here and
there hacking in goto's.  

						Roger Reid