Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!uunet!seismo!gatech!bloom-beacon!wesommer
From: wesommer@athena.mit.edu (William Sommerfeld)
Newsgroups: comp.lang.c
Subject: Re: goto's in C: an opinion...
Message-ID: <1164@bloom-beacon.MIT.EDU>
Date: Fri, 17-Jul-87 23:32:49 EDT
Article-I.D.: bloom-be.1164
Posted: Fri Jul 17 23:32:49 1987
Date-Received: Sat, 18-Jul-87 18:28:27 EDT
References: <3289@bigburd.PRC.Unisys.COM> <7571@beta.UUCP>
Sender: daemon@bloom-beacon.MIT.EDU
Reply-To: wesommer@priam.UUCP (William Sommerfeld)
Organization: Massachusetts Institute of Technology
Lines: 78
Keywords: C, goto, style

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