The final word on GOTO (Don't I wish!)

T. William Wells bill at twwells.com
Thu Sep 14 12:03:24 AEST 1989


In article <7917 at goofy.megatest.UUCP> djones at megatest.UUCP (Dave Jones) writes:
: ) Well yeah, so would I. But what is the bug? I've just reread the code
: ) and don't see where I've broken it. I'm prepared to be red-faced
: ) because this has go to be something really obvious, but what?
:
: DON'T PANIC.

Good thing, my Panic Button is broken! I hit it too many times
already today. :-)

: Your face is going to be just fine. But it's lucky for me that I don't blush.
: You didn't misread it. I did. In fact, I read it half a dozen times before I saw
: the "break" at the end of the while-loop.
:
: Boy, that's wierd.
:
: No offense, but you won't catch me using this device. Different strokes,
: I guess.

Yeah. No doubt the strangeness of it will put many people off. Well
one day I just got so tired of icky argument parsing loops that I
devised a thing with a break past the bottom of the switch. Once I
realized that this solved many cases of the two level break problem,
I started using it fairly regularly. For me it is now a familiar
idiom; I don't have any problem with it any more. My feeling is that C
idiom is already sufficiently strange, what's one more wierdness among
programmers? :-)

As far as I'm concerned, *every* method of solving the two level
break problem is flawed in one way or another. The right solution is
a language innovation, but I'm not going to hold my breath.

But anyway, that isn't really why I'm posting. You may recall an
article I wrote on this subject the last time it came 'round (over in
comp.misc). I'm enclosing an updated version here because it really
*is* the final word on goto. (Ok, it certainly could be elaborated.
But as the guy said, all else is commentary....)

---

Under ordinary circumstances, there is exactly one place I know of
where a human C coder might properly use a goto. This is to implement
multi-level breaks and continues.

I say this, having written hundreds of thousands of C code, and
managed several programmers also writing mainly C code. I have
programmed in C since 1981 and have NEVER used a goto. We have
uncounted megabytes of C code written in-house. There are no gotos in
it.

With that up front, let me say why the goto discussion is really
fruitless: it completely misses the point. People have observed that
gotos are used in a lot of bad code. From this it is concluded that
gotos are bad. This is really bad logic. Try this: programmers have
been observed to write bad code; therefore, programmers are bad!

THERE IS NOTHING INHERENTLY WRONG WITH GOTO. And how do I reconcile
with my comments above? Wait and see...

One important point in the structured programming argument is this:
every program has a control structure; some of these control
structures are better than others. Whether you use gotos or some other
language feature to implement the control structure does not change
what the control structure is, nor does it affect (much) the goodness
of the control structure.

The quality of your program is strongly influenced by the quality of
its control structures. Furthermore, you want that control structure
to be obvious and understandable to the reader of the program. This
implies that you use language features that make your use of a
control structure as obvious as possible.

So, the first question should be: what are the good control
structures?

The second question is then: given a particular language, which
control structures should be implemented? And how?

Ok, so what makes a control structure good? Well, the basic answers
are: a control structure is good if it is

    1) appropriate to solving programming problems.
    2) easy to write.
    3) easy to understand.
    4) easy to maintain.
    5) ... add your own as long as they do not contradict the above

There are obviously lots of control structures that meet these
requirements and you do not have to use all of them. In fact, you
should pick a set of those which are most appropriate for your
programming environment and use just those. This set should be, in
some sense, a minimum one; for example, if you have two control
structures which can accomplish the same thing, but one is easier to
use than the other (for you), pick the easier one and forget the
other. If you code a repeat forever loop as while (1), always do it
that way, don't switch to for(;;) every third tuesday. All other
things being equal, a smaller number of control structures helps make
your program easier to understand.

Now, I hope my claim about our C programs is understandable. But if
not, here is what it amounts to: we have chosen a set of control
structures which is appropriate to programming in C, for the kind of
programming tasks that we do. It happens that, while this set of
control structures includes multi-level breaks and continues (which
could be implemented with a goto), we have never had need to implement
one with a goto. Given the amount of code involved, it seems to me
that one might never have a good reason to use an explicit goto in C
code.

For other languages, one would come to a different conclusion. In
assembly language (unless you have a fairly powerful assembler),
*every* control structure is implemented with a goto. In COBOL, many
control structures are implemented with a goto. In Pascal, there are
just a few things that are best expressed with a goto. In most
varieties of Lisp, there is, from what I've seen, always a better way
than a goto.

There is, however, a reason to avoid naked gotos in your code: for
all other keywords, the control structure being implemented is
obvious. But for goto it isn't. One way to make the control structure
obvious is to properly name the target of the loop (e.g.,
end_of_main_traversal_loop). Another is to make the control structure
obvious by clothing the goto in some preprocessor magic. As an
example, suppose that you are using the state machine control
structure. One way to code it is:

	state = STATE_INIT;
	while (state != STATE_DONE) {
		switch (state) {
		case STATE_INIT:
		...
		}
	}

However, this is not the most efficient way to do it. If efficiency
were a concern (and you knew that you weren't going to deal with a
brain-damaged optimizer that won't optimize functions that have even
a single goto) you could also implement it as:

/* Wherever you see these macros being used, you will be seeing a
   state machine. The state macro defines the start of a state. The
   enter_state macro causes a transfer of control to another state of
   the same machine. The leave macro sends you to the end of the
   machine, the end_machine macro marks the place where the machine
   ends. */

#ifndef SDEBUG
#define state(m, label)       m##label:;
#define end_machine(m)        m##_finish:;
#else
#define state(m, label)                 printf("warning: falling though\n"); \
			      m##label: printf("entering state " #label \
					       " of machine " #m "\n");
#define end_machine(m)        m##_finish:printf("leaving machine " #m "\n");
#endif
#define enter_state(m, label) goto m##label
#define leave(m)              goto m##_finish

	state(input_interp, INIT)
		... code for the INIT state
		enter_state(input_interp, MORE);

	state(input_interp, MORE)
		... code for the MORE state
		if (nomore) {
			leave(input_interp);
		} else if (error) {
			enter_state(input_interp, RECOVER);
		}
		enter_state(input_interp, MORE);

	state(input_interp, RECOVER)
		... code for the RECOVER state
		enter_state(input_interp, FUDGE_INPUT);

	...

	end_machine(input_interp)

Some of you will no doubt be thinking: but why should I go to all
this effort when I could just use the goto directly? Well, if you do
only one kind of thing with goto, I don't really see any reason why
not (but I do think your program should include a comment saying what
control structure you have implemented using the goto). If, however,
you have more than one way of using goto, you should clothe the gotos
somehow so that the reader of the program knows what control
structures each of your gotos belongs to.

---
Bill                    { uunet | novavax | ankh | sunvice } !twwells!bill
bill at twwells.com



More information about the Comp.lang.c mailing list