Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!uunet!seismo!think!rst
From: rst@think.COM (Robert Thau)
Newsgroups: comp.lang.c
Subject: Re: goto's in C: an opinion...
Message-ID: <6603@think.UUCP>
Date: Sat, 18-Jul-87 13:57:14 EDT
Article-I.D.: think.6603
Posted: Sat Jul 18 13:57:14 1987
Date-Received: Sun, 19-Jul-87 01:00:35 EDT
References: <3289@bigburd.PRC.Unisys.COM> <7571@beta.UUCP>
Sender: news@think.UUCP
Reply-To: rst@godot.think.com.UUCP (Robert Thau)
Organization: Thinking Machines Corporation, Cambridge, MA
Lines: 121
Keywords: C, goto, style

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 ...