[comp.lang.c] goto's

chris@mimsy.UUCP (Chris Torek) (07/25/87)

In article <960@fmsrl7.UUCP> grazier@fmsrl7.UUCP (Kevin Grazier) writes:
>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.

To prove otherwise to yourself, consider any program that contains
at least one `goto' statement.  The section of code to which this
branches is either normally reachable, or reachable only by a goto.

(The following may be flawed; I have not bothered to check it
carefully.  Nonetheless the general idea ought to be right.)

Case I: Normally reachable.

Replace the beginning of the program with
    
	while not prog_done do

and the end of the program with

	if not doing_goto or did_goto then prog_done <- true; fi;
	end while;

Now protect every single statement except those which would be
executed by the `goto' with

	if not doing_goto then <original statement>; fi;

At the beginning of the section performed by the goto, add

	if doing_goto then did_goto <- true; fi;

Change the goto statement to

	doing_goto <- true;

Add two global variables:

	boolean doing_goto <- false, did_goto <- false;

Case II: Not normally reachable.

Move the unreachable code anywhere within the scope of the main
program and protect it with `if not doing_goto then <code>; fi;'.
The problem has now been reduced to case I.

This can be repeated for all remaining goto statements, using
different variable names for the pair of booleans.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
Domain:	chris@mimsy.umd.edu	Path:	seismo!mi (Ssed to

chris@mimsy.UUCP (Chris Torek) (07/26/87)

In article <7687@mimsy.UUCP> I mentioned
>(The following may be flawed; ...

It sure was.

>Nonetheless the general idea ought to be right.)

... which I still think is true.

The general idea, in case it was obscured by the (bogus) details,
is to add enough booleans and, if necessary, a loop around the
entire program, so that each goto can be replaced by a sequential
flow to the place to which the goto went, where the gone-to code
then executes.  Doing this is nontrivial, but, I think, always
possible.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
Domain:	chris@mimsy.umd.edu	Path:	seismo!mimsy!chris

kopaz@rdlvax.UUCP (John Anthony 'Echo' Kopaz) (07/28/87)

Posting-Front-End: GNU Emacs 18.47.1 of Thu Jul  9 1987 on rdlvax (berkeley-unix)



in your article you write:
>To prove otherwise to yourself, consider any program that contains
>at least one `goto' statement.  The section of code to which this
>branches is either normally reachable, or reachable only by a goto.

>(The following may be flawed; I have not bothered to check it
>carefully.  Nonetheless the general idea ought to be right.)

>Case I: Normally reachable.

>Replace the beginning of the program with
    
>	while not prog_done do

>and the end of the program with

>	if not doing_goto or did_goto then prog_done <- true; fi;
>	end while;

>Now protect every single statement except those which would be
>executed by the `goto' with

>	if not doing_goto then <original statement>; fi;

>At the beginning of the section performed by the goto, add

>	if doing_goto then did_goto <- true; fi;

>Change the goto statement to

>	doing_goto <- true;

>Add two global variables:

>	boolean doing_goto <- false, did_goto <- false;

>Case II: Not normally reachable.

>Move the unreachable code anywhere within the scope of the main
>program and protect it with `if not doing_goto then <code>; fi;'.
>The problem has now been reduced to case I.

>This can be repeated for all remaining goto statements, using
>different variable names for the pair of booleans.
--

i don't think all that warped boolean logic is in the best interest to 
readable code. it has a FORTRAN :~{ flavor to it.

in the interest of readability, maintainability, and flexability ....
		(and a couple 'bilities i may not have mentioned :~))
i think that gotos could be justified.  to say otherwise is to limit a 
                   ^^^^^^^^  - not are or should be
choice in your professional behavior. (that is not very professional.)  

there are three distinct aspects in program design: data structures, 
algorythms, and languages. all of which impact on the others.  limiting 
a choice in one will limit choices in the others.  

another way of looking at it is thus:

			The Law of Requisite Variety
the factor with the most choices will be the dominant (say: controling) factor.
			1 choice ->	robot
			2 choices ->	delemma
			3+ choices ->	FREEDOM!!!

this is my opinion, you are not required to agree/disagree, it is just the way 
i design.

			tanx.
			echo.
-- 
                        john a. kopaz [aka echo.]
     associate research scientist / software engineer / test specimen
voice: 213-410-1244 -- fax: 213-216-5940 -- corporeal: rdl
arpa : kopaz@rdlvax.rdl.com                            5721 w. slauson ave.
uucp : ...!{psivax,csun,sdcrdcf,ttidca}!rdlvax!kopaz   culver city, ca 90320

stuart@bms-at.UUCP (Stuart D. Gathman) (07/28/87)

Knuth has an excellent method for converting any program, no matter how
convoluted, to perfectly structured code with no goto's.

The following pascal template will give you the idea:

PROGRAM DOANYTHING;

VAR 
  P : INTEGER;

BEGIN

  WHILE P != 0 DO
  BEGIN
    IF P = 1 THEN
    BEGIN
      (* DO STEP 1 *)
      P := (* STEP TO PERFORM AFTER 1 *)
    END;
    IF P = 2 THEN
    BEGIN
      (* DO STEP 2 *)
      P := (* STEP TO PERFORM AFTER 2 *)
    END;
    IF P = 3 THEN
    BEGIN
      (* DO STEP 2 *)
      P := (* STEP TO PERFORM AFTER 3 *)
    END;
    (* NOTE: SET P TO 0 WHEN DONE *)
  END;

END.
-- 
Stuart D. Gathman	<stuart@bms-at.uucp>
			<..!seismo!dgis!bms-at!stuart>

tdavis@athena.mit.edu (Timothy L. Davis) (07/29/87)

In article <465@bms-at.UUCP> stuart@bms-at.UUCP (Stuart D. Gathman) writes:
>
>Knuth has an excellent method for converting any program, no matter how
>convoluted, to perfectly structured code with no goto's.
>...
>    IF P = 1 THEN
>      (* DO STEP 1 *)
>      P := (* STEP TO PERFORM AFTER 1 *)
>    IF P = 2 THEN
>      (* DO STEP 2 *)
>      P := (* STEP TO PERFORM AFTER 2 *)
>...

I am just finishing a modification of a program which used this precise
system for "computed" gotos.  What a mess!  It was nearly impossible to read 
clearly. The little assignment statements, which were in effect gotos, were 
MUCH harder to follow than goto's themselves.  If you are going to write 
spaghetti code, you might as well use the spaghetti construct!  

Tim Davis
tdavis@ATHENA.MIT.EDU
...mit-eddie!mit-athena!tdavis

rpw3@amdcad.AMD.COM (Rob Warnock) (07/30/87)

In article <1217@bloom-beacon.MIT.EDU> tdavis@ATHENA.MIT.EDU (Timothy L. Davis)
writes:
+---------------
| In article <465@bms-at.UUCP> stuart@bms-at.UUCP (Stuart D. Gathman) writes:
| >Knuth has an excellent method for converting any program, no matter how
| >convoluted, to perfectly structured code with no goto's.
| I am just finishing a modification of a program which used this precise
| system for "computed" gotos.  What a mess!  It was nearly impossible to read 
+---------------

This is *precisely* what led Bill Wulf (over a decade ago) to publish ago a
short note in ACM SIGPLAN(?) entitled "Global Variable Considered Harmful"
(following Dijkstra's earlier paper "Goto Considered Harmful").

It is not the "goto" per se which is harmful, but the spagetti control
flow which results from an undisciplined use of it, and the resulting human
difficulty in proving that all possible combinations of that control flow
yield the correct results.  (Also see Miller's classic "The Magical Number
Seven Plus Or Minus Two".)

Remember, Dijkstra's definition of "structured programming" was *not* a
simplistic "no gotos", but rather an unceasing vigilence against all manner
of "complexity generators".  Global variables (*all* global variables) create
the same potential for unbridled complexity.

On the other hand, while "no gotos" and "no global variables" are very
useful heuristics, following them doesn't guarantee success.  Murphy's
Something-Or-Otherth Law: "It ain't that simple."


Rob Warnock
Systems Architecture Consultant

UUCP:	  {amdcad,fortune,sun,attmail}!redwood!rpw3
ATTmail:  !rpw3
DDD:	  (415)572-2607
USPS:	  627 26th Ave, San Mateo, CA  94403

farren@hoptoad.uucp (Mike Farren) (07/30/87)

Seems to me that IBM, while not normally considered C experts, have
something to say about the "no gotos/no globals" controversy:  THINK!

I can't see any reason not to use a goto if it makes my program flow
more legible (and that's to ME, not to a hypothetical optimizing
compiler - all the optimization in the world isn't going to help if
I'm confused as to the basic data flow).  Likewise, I can't see any
reason TO use one if other constructs are available that work as well,
have less undesirable side effects, and are clear.

The ultimate goal, I think, is to produce programs which are
error-free and maintainable, and in pursuit of that goal, I will use
any constructs available to me in the language I'm working with.


-- 
----------------
                 "... if the church put in half the time on covetousness
Mike Farren      that it does on lust, this would be a better world ..."
hoptoad!farren       Garrison Keillor, "Lake Wobegon Aq----

chris@mimsy.UUCP (Chris Torek) (07/31/87)

In article <105@rdlvax.UUCP> kopaz@rdlvax.UUCP (John Anthony 'Echo'
Kopaz) writes:
[regarding mechanically removing goto statements by adding booleans]
>i don't think all that warped boolean logic is in the best interest to 
>readable code.

Certainly not.  But someone made the claim that there are algorithms
that require goto statements; this is not the case.  On the other hand,
modern imperative languages have all the constructs they do for good
reason:  You can write what you mean.

Clear code requires two things: knowing what you mean; and writing
that.  If you *really mean* `go do something special', by all means,
write that.  But if you mean something that can be expressed *simply*
(this is important) using a weaker construct (`weaker' here means
`less able to affect control flow': `while' is weaker than `goto'),
use the weaker form.  It says less, and hence is easier to understand.

A loop that reads

	while ((in = getinput()) != END_OF_INPUT)
		(*op[in])(in);

is using a very strong control operation, yet may well be easier to
understand than a whole series of weak `if's:

	while ((in = getinput()) != END_OF_INPUT) {
		if (in < 4) {
			...
		} else if (in == 4) {
			...
		} else if (in < 7) {
			...
		} ...
	}

Deciding when the stronger construct makes the code clearer is an
art, and different people will certainly have different aesthetics.
So what else is new? :-)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
Domain:	chris@mimsy.umd.edu	Path:	seismo!mimsy!chris

rblieva@cs.vu.nl (Roemer b Lievaart) (07/31/87)

Although I usually hate goto's, here is an example which I used
myself two or three times:


	switch( expr ) {

	defolt:
	default:	/* code, probably error handler */
			break ;
	const1:		...
	const2:		if ( ! const2_allowed )
				goto defolt ;
			else ...
	const3:		...
	  ...
	}

Now this is just another example which seems to me perfectly
readable. But I must say, far most goto's I find detesting.
Yech!
One shouldn't get used to goto's, that's my opinion.

	Let's live,

		Roemer B. Lievaart...
		Amsterdam.

Q: How many IBM cpu's does it take to do a logical right shift?
A: 33. 1 to hold the bits and 32 to push the register.