[misc.misc] The "evil" GOTO

mirk@warwick.UUCP (Mike Taylor) (05/04/89)

In article <3, I think> gould@rosemary.cs.reading.ac.uk (Adrian Gould) writes:
> Lets eradicate the GOTO from all languages.

I hate it when people say things like that; As if you can just wave a
magic wand over a language by excising GOTO, and everything will be
alright.  Listen, just 'cause Quiche-eater Wirth connected GOTOs with
lack of structure geenrally, doesn't mean either that (A) ALL use of
GOTO is unstructured and obfuscatory, or that (B) ALL obfuscated code
is due to use of GOTO -- so why is it that so many people seem to
believe these myths?

How many times have you seen this kind of code?

	printf ("Enter your sex: ");
	while (sex != "m" && sex != "f") {
		gets (sex);
		if  (sex != "m" && sex != "f")
			printf ("<m> or <f> only: ");
	}

Why make the test twice?  Huh?  Huh?  Answer me that, all you obsessed
anti-GOTO campaigners.  The *natural* way to express the above is:

	printf ("Enter your sex: ");
LABEL:	gets (sex);
	if (sex != "m" && sex != "f") {
		printf ("<m> or <f> only: ");
		GOTO LABEL;
	}

Better examples abound, but in time honoured way, elude me now that I
need them.  How many times have you seen people using "for (;;;) ...
break;" when you *know* that by "break" they mean "GOTO"?  In many
situations GOTO is natural - the response of a thinking being to it is
to traid to know when those times are.  Clearly irresponsible use of
GOTO is bad; clearly spaghetti-junction programs written in languages
with no other flow-control are bad (Frog knows how APL people manage!)
But let's get this in perspective.  It isn't GOTO's fault.  It's yours
for using it badly.

It makes me laugh when people push Ada as a good real-time langauge
because iof its "powerful exception-handling".  "Exception-handling".
Do you know what that means?  Yup, you guessed it, it's a fancy word
for GOTO.  Luverly, Eh?  Dress it up to look nice'n'respectable,
install it as a fabulous feature in a DoD-sponsored langauge-to-end-
all-languages, and everyone loves it.  Well they ain't fooling me.
I know goto when I see it.

The reason Ada seems more powerful for having GOTO is simply because
the programming paradigm that is pushed together with Ada causes the
programmer to use GOTO in a disciplined way.  THAT is the answer to
the GOTO problem.  Teach people to recognise WHEN to use it, and teach
them to know HOW to use it.
______________________________________________________________________________
Mike Taylor - {Christ,M{athemat,us}ic}ian ...  Email to: mirk@uk.ac.warwick.cs
Unkle Mirk sez: "G G7/B C F G G7/B B7 Em; Dm7 G7/B C Gdim7 G D C Gdim7 G D Cm"

rang@cpsin3.cps.msu.edu (Anton Rang) (05/05/89)

In article <1814@ubu.warwick.UUCP> mirk@warwick.UUCP (Mike Taylor) writes:

   [ ... ]  Listen, just 'cause Quiche-eater Wirth connected GOTOs with
					     ^^^^^
   lack of structure generally, doesn't mean either that (A) ALL use of
   GOTO is unstructured and obfuscatory, or that (B) ALL obfuscated code
   is due to use of GOTO -- so why is it that so many people seem to
   believe these myths?

It was Dijsktra [sp?].  Other than that, I perfectly agree!

+---------------------------+------------------------+-------------------+
| Anton Rang (grad student) | "VMS Forever!"         | VOTE on	         |
| Michigan State University | rang@cpswh.cps.msu.edu | rec.music.newage! |
+---------------------------+------------------------+-------------------+
| Send votes for/against rec.music.newage to "rang@cpswh.cps.msu.edu".   |
+---------------------------+------------------------+-------------------+

jlg@lanl.gov (Jim Giles) (05/05/89)

From article <1814@ubu.warwick.UUCP>, by mirk@warwick.UUCP (Mike Taylor):
> 	printf ("Enter your sex: ");
> LABEL:	gets (sex);
> 	if (sex != "m" && sex != "f") {
> 		printf ("<m> or <f> only: ");
> 		GOTO LABEL;
> 	}
> 
> Better examples abound, but in time honoured way, elude me now that I
> need them.  How many times have you seen people using "for (;;;) ...
> break;" when you *know* that by "break" they mean "GOTO"?  

Actually, in the above example, "break" is a better way.  This is the
classic "loop and a half" problem for which the "break" statement
exists.  So the following is a better suggestion:

      printf ("Enter your sex: ");
      for (;;) {
         gets (sex);
         if (sex == "m" || sex == "f") break;
         printf ("<m> or <f> only: ");
      }

Note: since C doesn't have multi-level breaks, GOTO must be used to escape
from nested constructs.

This does not mean that I oppose GOTOs in a programming language.  In fact,
there _are_ situations in which GOTO is the most readible and efficient
means of flow control.  Consider the situation in which two branches of
a conditional merge again:

      if (cond1) {
         [...A...]   /* lots of code */
         goto LABEL;}
      else if (cond2) {
LABEL:   [...B...]   /* lots more code */
      }

After executing sequence 'A', the rest of the action for 'cond1' is identical
to the action for 'cond2'.  The suggested "structured" fixes to this sequence
include:
   1) put sequence 'B' in a separate procedure and call it from both places

   2) duplicate sequence 'b' in both places

   3) set a flag variable to hold the condition that 'B' needs to be 
      executed, and put 'B' after the original 'if' sequence enclosed
      in another conditional.

The problem with 1) is that it introduces a speed penalties due to the
procedure call - not efficient.  Solution 2) imposes a code space penalty
as well as making code maintenance difficult (you must always remember to
update _both_ versions of 'B').  Solution 3) imposes a speed penalty for
setting and testing the flag, a space penalty for the extra variable and
the code to manipulate it, and it is _less_ readible than the version
already given above!

This conditional-merge problem is one of the only two places where I still
use GOTO in my programs - the other case is the classic error-exit from
deep within a nested structure (exception handling, if available, would
satisfy this requirement).

Unfortunately, the above construct is illegal in many "structured"
programming languages (including - of all things - Fortran).  They seem
to feel that jumping into a compound statement from the outside is
bad practice.  Yet, I run into this case all the time (even on very short
programs (<1000 lines) I usually run into this at least once).  And there
is no "structured" way around it!

Note: I always make a distinction between well structured programs and
well "structured" programs.  The later are those which conform to the
anti-GOTO religion without regard to the actual quality of the code
itself.  A well "structured" program is often a very badly structured
one.

jik@athena.mit.edu (Jonathan I. Kamens) (05/05/89)

In article <1814@ubu.warwick.UUCP> mirk@uk.ac.warwick.cs (Mike Taylor) writes:
>How many times have you seen this kind of code?
>
>	printf ("Enter your sex: ");
>	while (sex != "m" && sex != "f") {
>		gets (sex);
>		if  (sex != "m" && sex != "f")
>			printf ("<m> or <f> only: ");
>	}

Indeed, this is a pretty bad example of where a goto would be useful,
because you are simply illustrating what the purpose of the C do ...
while construct is for:

do {
   fprintf(stdout, "Enter your sex (<m> or <f> only): ");
   fflush(stdout);
   fgets(stdin, sex, 2);
   fflush(stdin);
} while ((*sex != 'm') && (*sex != 'f'));

Granted, goto can have its uses, and exception handling is a prime
example, but don't go jumping to conclusions and saying that goto is
the most understandable method to use in a case where (at least in my
opinion) a more "structured" construct does a better job.

Jonathan Kamens			              USnail:
MIT Project Athena				410 Memorial Drive, No. 223F
jik@Athena.MIT.EDU				Cambridge, MA 02139-4318
Office: 617-253-4261			      Home: 617-225-8218

rang@cpsin3.cps.msu.edu (Anton Rang) (05/05/89)

In article <13113@lanl.gov> jlg@lanl.gov (Jim Giles) writes:

>   Actually, in the above example, "break" is a better way.  This is the
>   classic "loop and a half" problem for which the "break" statement
>   exists.  So the following is a better suggestion:
>
>	 printf ("Enter your sex: ");
>	 for (;;) {
>	    gets (sex);
>	    if (sex == "m" || sex == "f") break;
>	    printf ("<m> or <f> only: ");
>	 }
>
>   Note: since C doesn't have multi-level breaks, GOTO must be used to escape
>   from nested constructs.

This is ugly; it essentially transforms the code

	LABEL: get input
	       if (bad input)
		 print message
		 go back to label

into

	LABEL: get input
	       if (good input)
		 goto LABEL2
	       print message
	       go back to label
	LABEL2:

Now you have two places where control jumps around, instead of just
one.  'break' has its uses, perhaps, but this isn't one of them
(IMHO).  Actually, I feel that 'break' should usually be replaced by
an explicit goto (heresy!).  Why?  Because the place the break goes to
isn't explicit; you have to start matching up loops.  If you have lots
of nesting, this is quite a mess.
  Named loops in Ada are intended to alleviate this problem, and if
used properly seem to do a decent job.

+---------------------------+------------------------+-------------------+
| Anton Rang (grad student) | "VMS Forever!"         | VOTE on	         |
| Michigan State University | rang@cpswh.cps.msu.edu | rec.music.newage! |
+---------------------------+------------------------+-------------------+
| Send votes for/against rec.music.newage to "rang@cpswh.cps.msu.edu".   |
+---------------------------+------------------------+-------------------+

ked@garnet.berkeley.edu (Earl H. Kinmonth) (05/05/89)

Keywords: Guinness, phlegm, mackerel, intestines

>magic wand over a language by excising GOTO, and everything will be
>alright.  Listen, just 'cause Quiche-eater Wirth connected GOTOs with
>lack of structure geenrally, doesn't mean either that (A) ALL use of
>GOTO is unstructured and obfuscatory, or that (B) ALL obfuscated code
>is due to use of GOTO -- so why is it that so many people seem to

I began programming in 1968 on a CDC 1604. I used Fortran (when the
sucker did not force me to use binary). Thus, I am more than familiar
with the go to statement (including the conditional go to statement).

Since 1979 I have been programming in C. I have written C code into the
high six-figures (lines of code). There has not been one case where a
goto seemed appropriate. When I was tempted, reflection and analysis
convinced me that a goto solution was inappropriate.

This is not a quiche-eater's problem. I teach Japanese history by
profession, and could give a s__t one way or the other. I want code
that is efficient (where efficiency includes my time) and that I have
some hope of understanding a few months or years down the line. By my
standards, the goto s__ks.

Some months ago, I rewrote GNUtar (an early version) to run under
MSDOS. The original author, in the name of "efficiency" had used a
large number of goto(s). As is common with such programming, he had not
used prof to find out whether the goto really resulted in faster
execution. He had, however, succeeded in making the code extremely
difficult to read.

As for the example that was part of this original posting, the author
should learn to use the switch statement. The switch in C is in effect
a "conditonal goto" (to use the jargon I learned with the 1604 in
1968), but it is much, much easier to read.

Since my specialty is Japanese history (albeit built on an undergrad
education in EE), I probably should not be telling
!!!!!PROGRAMMERS!!!!! (bells, gongs, drum rolls, trumpet flourishes)
how to do their work. Based on substantial experience, I would
nevertheless suggest that if you are absolutely convinced of the need
for a goto, that section of the code should really be done in
assembler.

ked@garnet.berkeley.edu (Earl H. Kinmonth) (05/05/89)

>Indeed, this is a pretty bad example of where a goto would be useful,
>because you are simply illustrating what the purpose of the C do ...
>while construct is for:
>
>do {
>   fprintf(stdout, "Enter your sex (<m> or <f> only): ");
>   fflush(stdout);
>   fgets(stdin, sex, 2);
>   fflush(stdin);
>} while ((*sex != 'm') && (*sex != 'f'));

First, your C compiler must have a rather weird stdio library if it
requires you to to do explicit flushing.

Second, why not

	while(1)	{
		fputs("Sex (m or f) ",stdout);
		gets(ls);
		if(ls[0] == 'm')	return(ls[0]);
		else
		if(ls[0] == 'f')	return(ls[0]);
		}

as a subroutine?

tale@pawl.rpi.edu (David C Lawrence) (05/05/89)

In article <24047@agate.BERKELEY.EDU> ked@garnet.berkeley.edu
(Earl H. Kinmonth) writes:

> Second, why not
> ... [ deleted ] ...
>		gets(ls);
> ... [ deleted ] ...
> as a subroutine?

Because gets() is almost as evil as goto().  Can we say Internet Worm?

Dave
--
      tale@rpitsmts.bitnet, tale%mts@itsgw.rpi.edu, tale@pawl.rpi.edu

falk@sun.Eng.Sun.COM (Ed Falk) (05/05/89)

In article <24047@agate.BERKELEY.EDU>, ked@garnet.berkeley.edu (Earl H. Kinmonth) writes:
> 
> Second, why not
> 
> 	while(1)	{
> 		fputs("Sex (m or f) ",stdout);
> 		gets(ls);
> 		if(ls[0] == 'm')	return(ls[0]);
> 		else
> 		if(ls[0] == 'f')	return(ls[0]);
> 		}
> 
> as a subroutine?


YUK!  This is getting worse and worse.  A "return" is basicly a
GOTO to the end of the function.  Besides being nit-picky, there's
a LOT of reasons not to put returns in the middle of code; you're
sure to get bitten by that habit.  Supposing you later come back
and modify this function to allocate some resource and then free it
at the end before returning.  If you don't notice a return in the
middle of your code, you start eating resources.

-- 
		-ed falk, sun microsystems
		 sun!falk, falk@sun.com
		 card-carrying ACLU member.

arrom@aplcen.apl.jhu.edu (Ken Arromdee) (05/05/89)

>>	printf ("Enter your sex: ");
>>	while (sex != "m" && sex != "f") {
>>		gets (sex);
>>		if  (sex != "m" && sex != "f")
>>			printf ("<m> or <f> only: ");
>>	}
>do {
>   fprintf(stdout, "Enter your sex (<m> or <f> only): ");
>   fflush(stdout);
>   fgets(stdin, sex, 2);
>   fflush(stdin);
>} while ((*sex != 'm') && (*sex != 'f'));

This is not analogous.

The original example prints the "<m> or <f> only:" message only if the
input is not an "m" or "f".  This supposeedly analogous program prints it
every time.

I
_know_
I
can
change
the
>
but
beating
inews
this
way
_feels_
better...
--
"Do you know what this is????"  "No, what?"  "I don't know either..."
  -- Who said it, what story?

Kenneth Arromdee (UUCP: ....!jhunix!ins_akaa; BITNET: g49i0188@jhuvm;
     INTERNET: arromdee@crabcake.cs.jhu.edu) (please, no mail to arrom@aplcen)

ken@aiai.ed.ac.uk (Ken Johnson) (05/05/89)

In article <1814@ubu.warwick.UUCP> mirk@uk.ac.warwick.cs (Mike Taylor) writes:
>How many times have you seen this kind of code?
>
>	printf ("Enter your sex: ");
>	while (sex != "m" && sex != "f") {
>		gets (sex);
>		if  (sex != "m" && sex != "f")
>			printf ("<m> or <f> only: ");
>	}
>

I like doing it this way: (NB This is not correct C! But I think it is
a correct program structure for the problem.)


get_sex( )
{
	return(get_sex_sub("Enter your sex: "));
}

get_sex_sub(string)
{
	printf (string);
	gets(sex)
	return(
		(sex == 'm' || sex == 'f')
		?
		sex
		:
		get_sex_sub("<m> or <f> only: ")
	      );
}
-- 
Ken Johnson, AI Applications Institute, 80 South Bridge, Edinburgh EH1 1HN
E-mail ken@aiai.ed.ac.uk, phone 031-225 4464 extension 212
Annoy the Labour Party! Pay the Poll Tax!

jha@lfcs.ed.ac.uk (Jamie Andrews) (05/05/89)

In article <1814@ubu.warwick.UUCP> mirk@uk.ac.warwick.cs (Mike Taylor) writes:
>Why make the test twice?  Huh?  Huh?  Answer me that, all you obsessed
>anti-GOTO campaigners.  The *natural* way to express the above is:
>
>	printf ("Enter your sex: ");
>LABEL:	gets (sex);
>	if (sex != "m" && sex != "f") {
>		printf ("<m> or <f> only: ");
>		GOTO LABEL;
>	}


Death to GOTO!

	printf ("Enter your sex: ");
	while (1) {
		gets (sex);
		if (sex == "m" || sex == "f")
			break;
		else
			printf ("<m> or <f> only: ");
	}

Long live break!

--J.

lishka@uwslh.UUCP (a.k.a. Fish-Guts) (05/05/89)

In article <24044@agate.BERKELEY.EDU> ked@garnet.berkeley.edu (Earl H. Kinmonth) writes:
>
>Since 1979 I have been programming in C. I have written C code into the
>high six-figures (lines of code). There has not been one case where a
>goto seemed appropriate. When I was tempted, reflection and analysis
>convinced me that a goto solution was inappropriate.

     You may not have been writing code where "goto"'s can be a life
saver.  Here are two quotes from the writers of C and C++ on where
goto's are actually useful:

	From _The_C_Programming_Language_ by B. Kernighan & D. Ritchie:

	     C provides the infinitely-abusable _goto_ statement, and
	labels to branch to.  Formally, the _goto_ is never necessary,
	and in practice it is almost always easy to write code without
	it.  We have not used _goto_ in this book.
	     Nonetheless, we will suggest a few situations where _goto_'s
	may find a place.  The most common use is to abandon processing
	in some deeply nested structure, such as breaking out of two
	loops at once.  The _break_ statement cannot be used directly
	since it leaves only the innermost loop [...].  This organization
	is handy if the error-handling code is non-trivial, and if errors
	can occur in several places.  [...]
	     Code involving a _goto_ can always be written without one,
	though perhaps at the price of some repeated tests an extra
	variable. [...]
	     Although we are not dogmatic about the matter, it does seem
	that _goto_ statements should be used sparingly, if at all.


	From _The_C++_Programming_Language_ by B. Stroustrup:

	     C++ possesses the infamous _goto_. [...]  It has few uses
	in general high-level programming, but it can be very useful
	when a C++ program is generated by a program rather than written
	directly by a person [...].  The _goto_ can also be important in
	the rare cases when optimal efficiency is essential [..].
	     One of the few sensible uses of the _goto_ is to break out
	from a nested loop or switch [...].

     So there are the comments, "straight from the horses' mouthes!"
There are times (especially when writing recursive-descent compilers)
when the use of one _goto_ or longjmp() can save many, many additional
tests.  Note that the setjmp()/longjmp() functions are just a
_goto_/label equivalent that can jump across functions (by unwinding
the stack).  _Goto_ does have its place!
 
>Some months ago, I rewrote GNUtar (an early version) to run under
>MSDOS. The original author, in the name of "efficiency" had used a
>large number of goto(s). As is common with such programming, he had not
>used prof to find out whether the goto really resulted in faster
>execution. He had, however, succeeded in making the code extremely
>difficult to read.

     Goto, as implemented in an IBM PC compiler, may not be as
efficient in some memory models as the equivalent code without goto's
(because a jump across segments might be necessary).  However, goto's
can be much more efficient when all that is needed is a single
assembler instruction to implement the goto (I oughta know: I had to
implement this in an Ada-subset compiler for a graduate compiler course).

>As for the example that was part of this original posting, the author
>should learn to use the switch statement. The switch in C is in effect
>a "conditonal goto" (to use the jargon I learned with the 1604 in
>1968), but it is much, much easier to read.

     The _switch_ statement is a "conditional goto," but only for
constants.  Much better is the (cond ...) conditional statement in
Lisp, or the _case_ statement in Ada.  There are many times when I
wish C would allow variables (and not just constants) after the _case_
keywords! 

>Since my specialty is Japanese history (albeit built on an undergrad
>education in EE), I probably should not be telling
>!!!!!PROGRAMMERS!!!!! (bells, gongs, drum rolls, trumpet flourishes)
>how to do their work. 

     You seem to have more experience writing code than many
"programmers," and your comments are good.  However, I still maintain
that there are some cases where good use of a goto can make code much
more "readable," and can save a helluva lot of additional tests that
shouldn't be necessary.  As long as it is not abused, _goto_ and
setjmp()/longjmp() can be very useful. 

>Based on substantial experience, I would
>nevertheless suggest that if you are absolutely convinced of the need
>for a goto, that section of the code should really be done in
>assembler.

     Talk about making the code unreadable by using a _goto_!
Including assembler in a C program will really make it unreadable.-- 
Christopher Lishka                 ...!{rutgers|ucbvax|...}!uwvax!uwslh!lishka
Wisconsin State Lab of Hygiene                   lishka%uwslh.uucp@cs.wisc.edu
Immunology Section  (608)262-1617                            lishka@uwslh.uucp

		 "I'm not aware of too many things...
		  I know what I know if you know what I mean"
		    -- Edie Brickell & New Bohemians

rang@cpsin3.cps.msu.edu (Anton Rang) (05/05/89)

In article <24044@agate.BERKELEY.EDU> ked@garnet.berkeley.edu (Earl H. Kinmonth) writes:

>Since 1979 I have been programming in C. I have written C code into the
>high six-figures (lines of code). There has not been one case where a
>goto seemed appropriate. When I was tempted, reflection and analysis
>convinced me that a goto solution was inappropriate.

  Not one case?  I haven't been programming in C that long, but I've
run into cases where a 'goto' is clearer than any of the other
solutions.  There is usually another way to do it, but often the goto
seems best (especially for exception handling, though not always).
  Partly, this is because I dislike some of C's "features".  Returning
from the middle of a function fred() is "more evil" (IMHO) than making
a label "end_of_fred" and using "goto end_of_fred".  Why?  Because
there is only one entry to and exit from the function (as somebody
else pointed out, this is useful if you're allocating resources etc.)
  Using "break" is OK for small loops, but not good for huge ones.
Why?  You can't tell where the break goes without going through the
loop, balancing "{" and "}".  Also, if you ever move the code with the
break into another loop, you're now breaking from the wrong loop!
Named loops, or labels "end_while_n_loop" avoid this problem.
  Exception handling is the worst problem.  I used to write functions
which had millions of nested if statements, because I had been
thoroughly indoctrinated with "GOTO is EVIL!".  I'd write code that
would be "call function. If success, { call function.  If success, {
call function. [ ad infinitum ] } } " .  Much easier to have a label
at the end of the function to handle it--easier to write, easier to
read, and much easier to change.
  Incidentally, using GOTO in these ways--always to get out of a
structure--doesn't seriously hurt compiler optimization, because you
shouldn't be breaking up basic blocks in the process (jumping into the
middle of a sequence of statements is what's evil, GOTO's not evil).

> Based on substantial experience, I would
>nevertheless suggest that if you are absolutely convinced of the need
>for a goto, that section of the code should really be done in
>assembler.

  Assembler???  Why should I sacrifice readability, and (some)
portability, just because I need (or want) a "goto"?

+---------------------------+------------------------+-------------------+
| Anton Rang (grad student) | "VMS Forever!"         | VOTE on	         |
| Michigan State University | rang@cpswh.cps.msu.edu | rec.music.newage! |
+---------------------------+------------------------+-------------------+
| Send votes for/against rec.music.newage to "rang@cpswh.cps.msu.edu".   |
+---------------------------+------------------------+-------------------+

hollombe@ttidca.TTI.COM (The Polymath) (05/06/89)

In article <1814@ubu.warwick.UUCP> mirk@uk.ac.warwick.cs (Mike Taylor) writes:
}In article <3, I think> gould@rosemary.cs.reading.ac.uk (Adrian Gould) writes:
}> Lets eradicate the GOTO from all languages.
}
}I hate it when people say things like that; As if you can just wave a
}magic wand over a language by excising GOTO, and everything will be
}alright.  Listen, just 'cause Quiche-eater Wirth connected GOTOs with

It was Dijkstra.

}lack of structure geenrally, doesn't mean either that (A) ALL use of
}GOTO is unstructured and obfuscatory, or that (B) ALL obfuscated code
}is due to use of GOTO ...

}How many times have you seen this kind of code?
}
}	printf ("Enter your sex: ");
}	while (sex != "m" && sex != "f") {
}		gets (sex);
}		if  (sex != "m" && sex != "f")
}			printf ("<m> or <f> only: ");
}	}
}

Thankfully, not very often (but then, I haven't got around to teaching an
intro to programming course, yet).  Here's how it should be done:

     do
     {
	  printf ("\nEnter your sex (m or f): ")
	  if (EOF == (sex = getchar())
	       perror ("getchar() error");
     }
     while ((sex != 'm') && (sex != 'f'))

Generally, a little thought and analysis can eliminate the need for nearly
all GOTOs quite elegantly.

}... How many times have you seen people using "for (;;;) ...
}break;" when you *know* that by "break" they mean "GOTO"? ...

If they'd meant goto they'd have said goto.  The construct does exist in
C. "break" is not equivalent.  It's much more limited and less likely to
get you into trouble.

}... In many
}situations GOTO is natural ...

In a few situations it has its uses.

}... Clearly irresponsible use of
}GOTO is bad; clearly spaghetti-junction programs written in languages
}with no other flow-control are bad (Frog knows how APL people manage!)
}But let's get this in perspective.  It isn't GOTO's fault.  It's yours
}for using it badly.

True.  The best quote I've heard on the subject was from some CS lecturer:

     "I sometimes use GOTOs.  I also use guns.  I _don't_ let children
     play with them."

}It makes me laugh when people push Ada as a good real-time langauge
}because iof its "powerful exception-handling".  "Exception-handling".
}Do you know what that means?  Yup, you guessed it, it's a fancy word
}for GOTO.  ...

No, it isn't.  As I recall, it's much closer to return().  An Ada function
either has its own exception handler or it passes the exception back to
the function that called it.

-- 
The Polymath (aka: Jerry Hollombe, hollombe@ttidca.tti.com)  Illegitimati Nil
Citicorp(+)TTI                                                 Carborundum
3100 Ocean Park Blvd.   (213) 452-9191, x2483
Santa Monica, CA  90405 {csun|philabs|psivax}!ttidca!hollombe

cetron@wasatch.utah.edu (Edward J Cetron) (05/06/89)

>from the middle of a function fred() is "more evil" (IMHO) than making
>a label "end_of_fred" and using "goto end_of_fred".  Why?  Because
>there is only one entry to and exit from the function (as somebody
>else pointed out, this is useful if you're allocating resources etc.)
	good point

>  Incidentally, using GOTO in these ways--always to get out of a
>structure--doesn't seriously hurt compiler optimization, because you
>shouldn't be breaking up basic blocks in the process (jumping into the
>middle of a sequence of statements is what's evil, GOTO's not evil).
>
	another good point
>
>  Assembler???  Why should I sacrifice readability, and (some)
>portability, just because I need (or want) a "goto"?
>
>| Anton Rang (grad student) | "VMS Forever!"         | VOTE on	         |


	This entire GOTO debate seems to be indicative of the quality of 
programmers currently available today.  To them, STRUCTURE is EVERYTHING.
They've even forgotten (or never learned WHY structured concepts are good).
But MOST IMPORTANTLY the forget that somewhere, somehow, a computer HAS to
execute these programs. Before I ever was taught about programming, I was
taught how the computers worked at the machine code level.  If once only
considers the computer at the HLL level, no matter how good and optimizing
compiler you have, you can still write stuff that is damned inefficient. 
	Maybe all these anti-GOTOites only write big COBOL programs which
are only used for Public Utility billing activities :-).  No matter what your
code is like in a HLL, it is STILL just a GOTO (JMP, BR, RTS...) to the CPU.
We've bred an entire generation of programmers and CS students who are so
concerned with 'ADA is better than C, and FORTRAN sucks' and 'STRUCTURE is
all that matters' and 'UNIX is it' that they have forgotten why programs are
written in the first place.  They sit in their " programmers' ivory tower" 
and forget that the program is supposed to do something in reality!  I would
rather have a clearly written program (structured or not) which accomplishes
what the PROGRAM is intended to do, without excess baggage and }'s JUST to
satisfy some STRUCTURED PROGRAMMING GOD, with GOTO's when necessary, AND WHICH
SHOW SOME UNDERSTANDING OF THE COMPUTER UNDER WHICH IT WILL RUN, than some
beautiful piece of code which when compiled/linked is nothing but dribble
to the CPU anyway.  
	Maybe that's why I only hire hardware oriented people.  You can teach
a h/w person to program, but most s/w types are confused by hardware.  I'm
not saying I prefer to code in assembler, but that one MUST know one's
environment.  It does not good to write exquisite Latin prose if your audience
speaks Chinese.

	Sorry for the flame, I'm just tired of interviewing smug new CS
students who know nothing about reality and using the right tools for the
job.  They make great followers, but we desparately need thinkers and leaders.

-ed cetron
cetron@wasatch.utah.edu

jlg@lanl.gov (Jim Giles) (05/06/89)

From article <2854@cps3xx.UUCP>, by rang@cpsin3.cps.msu.edu (Anton Rang):
>>	 printf ("Enter your sex: ");
>>	 for (;;) {
>>	    gets (sex);
>>	    if (sex == "m" || sex == "f") break;
>>	    printf ("<m> or <f> only: ");
>>	 }
> This is ugly; it essentially transforms the code
> [...] 
> into
> 
> 	LABEL: get input
> 	       if (good input)
> 		 goto LABEL2
> 	       print message
> 	       go back to label
> 	LABEL2:

You are exactly right.  I didn't say the feature was elegant, I said that
"loop-and-a-half" problems were the reason that "break" was introduced
into looping constructs (which occured in languages long before C was
invented).  The reason for "break" in "case" constructs only dmr can
answer 8-).
 
> [...]                              Because the place the break goes to
> isn't explicit; you have to start matching up loops.  If you have lots
> of nesting, this is quite a mess.
>   Named loops in Ada are intended to alleviate this problem, and if
> used properly seem to do a decent job.

I like the solution of named loops too.  But Ada puts all but the first
occurrance of the the label into the code rather than on the left margin.
The advantage of GOTOs (if any) was that you could easily find the target
of the branch by looking for the label.  Consider the example on page 5-8
of the Ada standard:

      MAIN_CYCLE: loop
                   --  initial statements
                   exit MAIN_CYCLE when FOUND;
                   --  final statements
                   end loop MAIN_CYCLE;

If the "initial" and "final" statement sequences were long and complicated
the "exit" and "end loop" could be difficult to identify.  (Even indentation
only helps a little if the code crosses page boundaries.)  In the Nemesis
programming language the above loop would be rendered as:

      MAIN_CYCLE: do
                  --  initial statements
      MAIN_CYCLE: exit if (FOUND)
                  --  final statements
      MAIN_CYCLE: end do

Here, no matter how long and complicated the statement sequences are, all
the controls for the "MAIN_CYCLE" loop are easily identified by scanning
the left margin of the code.  Note that the identifier "MAIN_CYCLE" is
the _name_ of a loop and _not_ a statement label (you can't GOTO MAIN_CYCLE).
Loop names _must_ appear on all control statements for the loop.  Unnamed
loops are allowed and must _not_ have a name on any control statement.

mark@cygnet.CYGNETSYSTEMS (Mark Quattrocchi) (05/06/89)

In article <11136@bloom-beacon.MIT.EDU> jik@athena.mit.edu (Jonathan I. Kamens) writes:
>In article <1814@ubu.warwick.UUCP> mirk@uk.ac.warwick.cs (Mike Taylor) writes:
>>How many times have you seen this kind of code?
>>
>>	printf ("Enter your sex: ");
>>	while (sex != "m" && sex != "f") {
>>		gets (sex);
>>		if  (sex != "m" && sex != "f")
>>			printf ("<m> or <f> only: ");
>>	}
>
>Indeed, this is a pretty bad example of where a goto would be useful,
>because you are simply illustrating what the purpose of the C do ...
>while construct is for:
>
>do {
>   fprintf(stdout, "Enter your sex (<m> or <f> only): ");
>   fflush(stdout);
>   fgets(stdin, sex, 2);
>   fflush(stdin);
>} while ((*sex != 'm') && (*sex != 'f'));
>
>Granted, goto can have its uses, and exception handling is a prime
>example, but don't go jumping to conclusions and saying that goto is
>the most understandable method to use in a case where (at least in my
>opinion) a more "structured" construct does a better job.
>

Speaking of jumping to conclusions, your code is not a one for one
equivalent of the original. Even though I agree with your interpretation,
you are cheating by combining the print statements together. Try again
only don't cheat.

mark@cygnet.CYGNETSYSTEMS (Mark Quattrocchi) (05/06/89)

In article <24047@agate.BERKELEY.EDU> ked@garnet.berkeley.edu (Earl H. Kinmonth) writes:
>>Indeed, this is a pretty bad example of where a goto would be useful,
>>because you are simply illustrating what the purpose of the C do ...
>>while construct is for:
>>
>>do {
>>   fprintf(stdout, "Enter your sex (<m> or <f> only): ");
>>   fflush(stdout);
>>   fgets(stdin, sex, 2);
>>   fflush(stdin);
>>} while ((*sex != 'm') && (*sex != 'f'));
>
>First, your C compiler must have a rather weird stdio library if it
>requires you to to do explicit flushing.
>
>Second, why not
>
>	while(1)	{
>		fputs("Sex (m or f) ",stdout);
>		gets(ls);
>		if(ls[0] == 'm')	return(ls[0]);
>		else
>		if(ls[0] == 'f')	return(ls[0]);
>		}
>
>as a subroutine?

This is great! Now we have two incorrect versions. Open eyes, read original,
duplicate. I suppose they did this because the program would be twice as long
if they made it compatible with the original.

Sorry, just testing our newsfeed (yeah that's it).

bill@twwells.uucp (T. William Wells) (05/07/89)

In article <1814@ubu.warwick.UUCP> mirk@uk.ac.warwick.cs (Mike Taylor) writes:
: How many times have you seen this kind of code?
:
:       printf ("Enter your sex: ");
:       while (sex != "m" && sex != "f") {
:               gets (sex);
:               if  (sex != "m" && sex != "f")
:                       printf ("<m> or <f> only: ");
:       }
:
: Why make the test twice?  Huh?  Huh?  Answer me that, all you obsessed
: anti-GOTO campaigners.  The *natural* way to express the above is:
:
:       printf ("Enter your sex: ");
: LABEL:        gets (sex);
:       if (sex != "m" && sex != "f") {
:               printf ("<m> or <f> only: ");
:               GOTO LABEL;
:       }

Why not:

	printf("Enter your sex: ");
	while (1) {
		gets(sex);
		if  (sex == "m" || sex == "f")
			break;
		}
		printf("<m> or <f> only: ");
	}

While it is might be the case that some things are better coded with
gotos than not, I've not seen any in many years of C programming.

: need them.  How many times have you seen people using "for (;;;) ...
: break;" when you *know* that by "break" they mean "GOTO"?  In many

Eh, sonny? The point of the break is that you *know* that it is a
goto, _and that you know where it is going *to*_.

: It makes me laugh when people push Ada as a good real-time langauge
: because iof its "powerful exception-handling".  "Exception-handling".
: Do you know what that means?  Yup, you guessed it, it's a fancy word
: for GOTO.  Luverly, Eh?  Dress it up to look nice'n'respectable,
: install it as a fabulous feature in a DoD-sponsored langauge-to-end-
: all-languages, and everyone loves it.  Well they ain't fooling me.
: I know goto when I see it.

*Every* control structure is a dressed-up goto. The point of the
control structures is to dress up the gotos so that you know what
they are *for*.

Here. I'll dig into my archives, and give you the following:

From novavax!uflorida!proxftl.UUCP!bill Thu May 19 15:52:54 1988
Path: proxftl!bill
From: bill@proxftl.UUCP (T. William Wells)
Newsgroups: comp.lang.c
Subject: Re: gotos
Summary: talking about gotos is fruitless
Message-ID: <197@proxftl.UUCP>
Date: 19 May 88 19:52:54 GMT
References: <1988Apr8.183815.3187@utzoo.uucp>, <449@goofy.megatest.UUCP> <528@wsccs.UUCP>
Organization: Proximity Technology, Ft. Lauderdale
Lines: 129

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

I say this, having managed (and written huge chunks of) a 17,000
line software system (and that is only the part we sell, and does
not include development tools).  I have programmed in C for six
years now and have NEVER used a goto.  We have uncounted
megabytes of C code written in-house.  None of it (to my
knowledge) contains a goto.  The closest thing we have to a goto
is setjmp/longjmp, used to implement a multi-level return (and
that is a recent change, one whose contemplation caused much
debate).

With that aside, let me explain why the goto discussion is really
fruitless.  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 WRONG WITH GOTO.  (And how do I reconcile with
my mouthing off above?  Wait and see...) The thing that is
screwed up is the control structures being implemented with the
gotos.

The whole point of the structured programming debate 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 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 obvious.

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

The second question should be: given a particular language, how
should the control structures be implemented?

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 them.  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.  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: I have chosen a set of
control structures which is appropriate to programming in C, for
the kind of programming tasks that I do.  It happens that, while
my set of control structures includes multi-level breaks and
continues (which would be implemented with a goto), I have never
had need of one.  Given the amount of code I write, it seems to
me that one might never need to use an explicit goto in C code.

Now that I think of it, here is a reason to avoid naked gotos in
C code: for all other constructs, the control structure being
implemented is obvious from the keywords employed.  This is not
true for goto.  Therefore, supposing that you have found a
control structure that you have to implement using gotos in C,
you should dress the goto up.  As an example, suppose that you
are using the state machine control structure.  I normally code
it as:

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

However, this is not the most efficient way to do it.  You could
also implement it as:

/* Wherever you see the macros state and nextstate being used,
   you will be seeing a state machine.  The state macro defines
   the start of a state.  The nextstate macro causes a transfer
   of control to another state of the same machine.  A state
   machine starts at a #define of statepref and ends with
   state(DONE).  */

#define dummy(x)        x
#define state(x)        dummy(statepref)x
#define nextstate(x)    goto dummy(statepref)x

#ifdef statepref
#undef statepref
#endif
#define statepref       STATE_
	state(INIT):
		... code for this state
		nextstate(DONE);
	... more states with the appropriate code
	state(DONE):
	... code after the state machine

(N.B.  I am aware that not all preprocessors will do what I want
here; for real portability, you would explicitly write the
prefixes.  Also, this method fails for nested state machines,
something I have occasionally had need of.)

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
this was all you did with goto, I don't really see any reason why
not (but I do think your program should include a comment saying
that you use goto for state machines and describes how you
structure it).  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 structure your goto belongs to.
(After all, a while is just a disguised goto :-)

bill@twwells.uucp (T. William Wells) (05/07/89)

In article <13113@lanl.gov> jlg@lanl.gov (Jim Giles) writes:
: This does not mean that I oppose GOTOs in a programming language.  In fact,
: there _are_ situations in which GOTO is the most readible and efficient
: means of flow control.  Consider the situation in which two branches of
: a conditional merge again:
:
:       if (cond1) {
:          [...A...]   /* lots of code */
:          goto LABEL;}
:       else if (cond2) {
: LABEL:   [...B...]   /* lots more code */
:       }
:
: After executing sequence 'A', the rest of the action for 'cond1' is identical
: to the action for 'cond2'.  The suggested "structured" fixes to this sequence
: include:
:    1) put sequence 'B' in a separate procedure and call it from both places
:
:    2) duplicate sequence 'b' in both places
:
:    3) set a flag variable to hold the condition that 'B' needs to be
:       executed, and put 'B' after the original 'if' sequence enclosed
:       in another conditional.
:
: The problem with 1) is that it introduces a speed penalties due to the
: procedure call - not efficient.

Agreed. Until the amount of code overwhelms the function call
overhead.

:                                  Solution 2) imposes a code space penalty
: as well as making code maintenance difficult (you must always remember to
: update _both_ versions of 'B').

Only half true. Many (most?) optimizers will recognize that the two
code sequences are identical and put the branch where you would
expect.

:                                  Solution 3) imposes a speed penalty for
: setting and testing the flag, a space penalty for the extra variable and
: the code to manipulate it, and it is _less_ readible than the version
: already given above!

Damn straight!

: This conditional-merge problem is one of the only two places where I still
: use GOTO in my programs - the other case is the classic error-exit from
: deep within a nested structure (exception handling, if available, would
: satisfy this requirement).

Be aware that a *single* goto in a function can cause many optimizers
to do nothing for the function. The reason for this is that many of
the better optimization techniques depend on the program having a
particular control structure and transforming an arbitrary program
into one that is acceptable is a hairy task.

: Unfortunately, the above construct is illegal in many "structured"
: programming languages (including - of all things - Fortran).  They seem
: to feel that jumping into a compound statement from the outside is
: bad practice.  Yet, I run into this case all the time (even on very short
: programs (<1000 lines) I usually run into this at least once).  And there
: is no "structured" way around it!

Me, I just live with the possible code duplication; the maintenance
headache is minor. By the time the code is large enough to make both
considerations less than minor, the function call overhead has become
trivial.

: Note: I always make a distinction between well structured programs and
: well "structured" programs.  The later are those which conform to the
: anti-GOTO religion without regard to the actual quality of the code
: itself.  A well "structured" program is often a very badly structured
: one.

Some of the worst structured programs I've seen have been written in
Modula 2. Some people think that merely following the structured
programming rules relieves them from the responsibility to think.

---
Bill                            { uunet | novavax } !twwells!bill

bill@twwells.uucp (T. William Wells) (05/07/89)

In article <2854@cps3xx.UUCP> rang@cpswh.cps.msu.edu (Anton Rang) writes:
: In article <13113@lanl.gov> jlg@lanl.gov (Jim Giles) writes:
: >      printf ("Enter your sex: ");
: >      for (;;) {
: >         gets (sex);
: >         if (sex == "m" || sex == "f") break;
: >         printf ("<m> or <f> only: ");
: >      }
: This is ugly; it essentially transforms the code
:
:       LABEL: get input
:              if (bad input)
:                print message
:                go back to label
:
: into
:
:       LABEL: get input
:              if (good input)
:                goto LABEL2
:              print message
:              go back to label
:       LABEL2:

Silly boy! No one gives a f*** how the code gets transformed. All we
have to read is the original. And the original is simplicity itself.

Would you please return to your ideological teachers and not bother
us with such irrelevancies?

: Now you have two places where control jumps around, instead of just
: one.  'break' has its uses, perhaps, but this isn't one of them
: (IMHO).  Actually, I feel that 'break' should usually be replaced by
: an explicit goto (heresy!).  Why?  Because the place the break goes to
: isn't explicit; you have to start matching up loops.  If you have lots
: of nesting, this is quite a mess.

By this you demonstrate that you have nothing worthwhile to say on
the subject.

You just don't understand the problem. Hell, you are *part* of the
problem.

Followups have been directed to alt.flame.

---
Bill                            { uunet | novavax } !twwells!bill

bill@twwells.uucp (T. William Wells) (05/07/89)

In article <103199@sun.Eng.Sun.COM> falk@sun.Eng.Sun.COM (Ed Falk) writes:
: YUK!  This is getting worse and worse.  A "return" is basicly a
: GOTO to the end of the function.  Besides being nit-picky, there's
: a LOT of reasons not to put returns in the middle of code; you're
: sure to get bitten by that habit.  Supposing you later come back
: and modify this function to allocate some resource and then free it
: at the end before returning.  If you don't notice a return in the
: middle of your code, you start eating resources.

Not reasonable. The "search" key in your favorite editor will easily
spot return. A failure to look for them is simply bad programming.

No, this is yet another example of misguided structured programming
ideology; the reasons for this went away when punch cards ceased to
be the normal method of entering programs.

---
Bill                            { uunet | novavax } !twwells!bill

jejones@mcrware.UUCP (James Jones) (05/07/89)

In article <1384@cygnet.CYGNETSYSTEMS> mark@cygnet.UUCP (Mark Quattrocchi) writes:
>This is great! Now we have two incorrect versions. Open eyes, read original,
>duplicate. I suppose they did this because the program would be twice as long
>if they made it compatible with the original.

/* Sorry, I couldn't resist changing the prompt... :-) */
printf("I want your sex: ");
while (gets(answer), (answer[0] != 'm' && answer[0] != 'f'))
	printf("<m> or <f> only: ");

Admittedly

(1) this version, like most of those I've seen so far, evades the question
    of gets() failure (though unlike the original version, it does *not* test
    the input before it's been read!), and it does presume that stdout is
    unbuffered so that the user sees the prompt (like the original)
(2) if the preparation for the checking were very much more complicated,
    one would have to drop back to using a break statement (where's Algol
    68 when you really need it?)
(3) the *true* dammit-structured-programming-is-a-hoax-and-only-good-enough-
    for-quiche-eaters-who-can't-really-program type would still object to
    this code because this loop may be followed by a redundant test of
    answer[0]!
 
and indeed, the objection in (3) could be a reasonable one, if the test for
validity were particularly complicated.

Let's all go read or reread Knuth, "Structured programming with goto
statements" (*Computing Surveys*, December 1974), so we can stop flogging
this dead horse, OK?  It hasn't *quite* been 25 years since Dijkstra's
famous letter, but it's close.

	James Jones

jik@athena.mit.edu (Jonathan I. Kamens) (05/08/89)

In article <24047@agate.BERKELEY.EDU> ked@garnet.berkeley.edu (Earl H. Kinmonth) writes:
>First, your C compiler must have a rather weird stdio library if it
>requires you to to do explicit flushing.

Some stdio libraries do not flush stdout unless you print a newline,
and when you are prompting for input you usually do not follow the
prompt with a newline.

Further, I flushed stdin because I wanted to be consistent :-) -- it
probably wan't necessary.

>Second, why not
>
> ...
>
>as a subroutine?

My point was not that the code segment I posted was the *best* way to
do the job, but rather that it was one way to do it that did not
require goto's.  You have shown another way.

As for why not as a subroutine, if you're only doing it once then
using a subroutine is a speed hit that you don't need (a small speed
hit, granted, but a speed hit nevertheless :-).  Inlining makes it run
faster.

You're suggestion is similar to the suggestion someone else posted of
using break to exit the loop when valid input was obtained.

Jonathan Kamens			              USnail:
MIT Project Athena				410 Memorial Drive, No. 223F
jik@Athena.MIT.EDU				Cambridge, MA 02139-4318
Office: 617-253-4261			      Home: 617-225-8218

ked@garnet.berkeley.edu (Earl H. Kinmonth) (05/08/89)

In article <11197@bloom-beacon.MIT.EDU> jik@athena.mit.edu (Jonathan I. Kamens) writes:
>In article <24047@agate.BERKELEY.EDU> ked@garnet.berkeley.edu (Earl H. Kinmonth) writes:

>As for why not as a subroutine, if you're only doing it once then
>using a subroutine is a speed hit that you don't need (a small speed
>hit, granted, but a speed hit nevertheless :-).  Inlining makes it run
>faster.

Please run this one past me again. Since I'm an historian and not a
programmer my mind must work differently. If you are doing it only once
and only micro-seconds are involved, the clearest form should prevail
(a subroutine rather than a goto). If you're going to do it a couple of
billion times and the function is a time pig, I can see sacrificing
readability to efficiency.

Of course, the logic stated in the previous paragraph would not hold if
(a) you write perfect code the first time and will never need to look
at it again; (b) only persons with your level of brilliance and your
programming experience ever look at your code.

Since your affiliaton is MIT, I must presume that both conditions hold.

jik@athena.mit.edu (Jonathan I. Kamens) (05/08/89)

In article <24127@agate.BERKELEY.EDU> ked@garnet.berkeley.edu (Earl H. Kinmonth) writes:
>Please run this one past me again. Since I'm an historian and not a
>programmer my mind must work differently. If you are doing it only once
>and only micro-seconds are involved, the clearest form should prevail
>(a subroutine rather than a goto). If you're going to do it a couple of
>billion times and the function is a time pig, I can see sacrificing
>readability to efficiency.

You're right, my answer was not well thought out.

>Of course, the logic stated in the previous paragraph would not hold if
>(a) you write perfect code the first time and will never need to look
>at it again; (b) only persons with your level of brilliance and your
>programming experience ever look at your code.
>
>Since your affiliaton is MIT, I must presume that both conditions hold.

Even if my posting was wrong, at least it was not obnoxious.  It seems
to me that this comment is, IMHO.

Jonathan Kamens			              USnail:
MIT Project Athena				410 Memorial Drive, No. 223F
jik@Athena.MIT.EDU				Cambridge, MA 02139-4318
Office: 617-253-4261			      Home: 617-225-8218

rjd@occrsh.ATT.COM (Randy_Davis) (05/08/89)

In article <1814@ubu.warwick.UUCP> mirk@uk.ac.warwick.cs (Mike Taylor) writes:
[...]
|How many times have you seen this kind of code?
|
|	printf ("Enter your sex: ");
|	while (sex != "m" && sex != "f") {
|		gets (sex);
|		if  (sex != "m" && sex != "f")
|			printf ("<m> or <f> only: ");
|	}
|
|Why make the test twice?  Huh?  Huh?  Answer me that, all you obsessed
|anti-GOTO campaigners.  The *natural* way to express the above is:
|
|	printf ("Enter your sex: ");
|LABEL:	gets (sex);
|	if (sex != "m" && sex != "f") {
|		printf ("<m> or <f> only: ");
|		GOTO LABEL;
|	}
|
|Better examples abound, but in time honoured way, elude me now that I
[...]

  This is the natural way for *me* to express the above example:

	printf ("Enter your sex: ");
	gets(sex);
	while(sex[0] != 'm' && sex[0] != 'f') {
		printf ("<m> or <f> only: ");
		gets(sex);
	}

  Now, admittedly, this is just the answer to *one* example *AND* it duplicates
one instruction (the gets) and thus makes the program incrementally larger.
YET, I have yet to see a GOTO program that could not have easily been written
without it....  Not neccessarily faster or more efficiently mind you - *I* am
not a "rabid anti-GOTOer", yet they rarely add to the readability of the
program, not that that is always an important attribute.

   It just seems to me to be the mark of a lazy programmer that doesn't take
the time to think of a way around the GOTO.  If he does know the way around
it and does it for a more efficient or more compact program, though - that's
another story.

Randy Davis					UUCP: ...(att!)ocrjd!randy
						      ...(att!)occrsh!rjd

hollombe@ttidca.TTI.COM (The Polymath) (05/09/89)

In article <2854@cps3xx.UUCP> rang@cpswh.cps.msu.edu (Anton Rang) writes:
}... Actually, I feel that 'break' should usually be replaced by
}an explicit goto (heresy!).  Why?  Because the place the break goes to
}isn't explicit; you have to start matching up loops.  ...

Where the break goes is _very_ specific.  It gets you out of the innermost
containing loop (or switch).  Where a goto goes is _anywhere_ it damn well
wants to.  I'd much rather match up a few braces (which, in _my_ coding
standard, are aligned vertically on the page) than search through thousands
of lines of code for a goto label.  Not to mention finding such a label in
the middle of a program and wondering how many goto statements go to it
and where they are.

-- 
The Polymath (aka: Jerry Hollombe, hollombe@ttidca.tti.com)  Illegitimati Nil
Citicorp(+)TTI                                                 Carborundum
3100 Ocean Park Blvd.   (213) 452-9191, x2483
Santa Monica, CA  90405 {csun|philabs|psivax}!ttidca!hollombe

welty@algol.steinmetz (richard welty) (05/09/89)

the above set of keywords (who supplied these, anyway?) exactly
sums up my own feelings on this topic ...

In article <1166@mcrware.UUCP> jejones@mcrware.UUCP (James Jones) writes:
>Let's all go read or reread Knuth, "Structured programming with goto
>statements" (*Computing Surveys*, December 1974), so we can stop flogging
>this dead horse, OK?  It hasn't *quite* been 25 years since Dijkstra's
>famous letter, but it's close.

actually, i think that everyone ought to go back and look at
Dijkstra's letter (geez, it's been 9 years since i read it)
and at some of the surrounding debate at the time ...

as i recall, Dijkstra was offering the observation that as
an experiment he and some collegues had started a systematic
effort to clarify a large algol 60 code, and noticed that as
the number of goto's declined, the number of bugs went down.

little did he know what a monster he had created ...

at this point in time, after some 16 years of programming,
the principle observations i have to offer is that if you
are `forced' to use a goto, then somebody (either you,
or your manglement, or that guy you inherited the code from
who got fired two weeks before you started your job) probably
made a bad decision.  there are occasions for gotos, but they
almost never arise in well-designed and well-implemented systems.

also, goto is NEVER a good substitute for a well-designed and
well-integrated exception-handling system.

note that i am excluding `structured programming using gotos'
as described in Knuth's article; in pre-fortran 77 days
when i coded in fortran i generally coded according to
Knuth's methods once i had learned about them.

as for basic, which started all of this flamage,
my personal feeling is that all basic programmers should
be taken out and shot, in order to put them out of their misery.

finally, i offer my own solution to the `sex' problem,
in Common Lisp (all this C is doing bad things
for my digestion.)  Oh, yes -- it also uses the
MIT Loop macro (i can see you lisp purists
wincing out there.)

this is, i believe, the original (i pinched this from
Jerry Hollombe's article, and am assuming it it the
original.)

}	printf ("Enter your sex: ");
}	while (sex != "m" && sex != "f") {
}		gets (sex);
}		if  (sex != "m" && sex != "f")
}			printf ("<m> or <f> only: ");
}	}

the above is a truly ugly piece of code, and i don't
believe that it really works, although i haven't written
more than 30 lines of C in the past 3 years.

the following was tested in lucid cl version 3.0.2, by the
way, and works perfectly.

(defun get-sex (&optional (stream *terminal-io*))
  "queries for user's sex on stream.
   returns nil if premature eof encountered
   premature ejaculation condition not handled"

  (write-line "Enter your sex (m or f)" stream)
  (loop for sex = (read-line stream nil nil)
        when (null sex) return nil                ; eof error
	when (or (string-equal sex "m") (string-equal sex "f"))
          return sex
        do
          (write-line "m or f only please")))

it would look uglier without the loop macro; something like
the following version which uses the simple
common lisp loop (note that (return <value>) in common
lisp is roughly comparable to C's break statement, except
that being function-oriented, lisp returns a value):

(defun get-sex (&optional (stream *terminal-io*))
  "queries for user's sex on stream.
   returns nil if premature eof encountered
   premature ejaculation condition not handled"

  (write-line "Enter your sex (m or f)" stream)
  (let (sex)
     (loop
        (setq sex (read-line stream nil nil))
        (when (null sex) (return nil))
	(when (or (string-equal sex "m") (string-equal sex "f"))
          (return sex))
        (write-line "m or f only please"))))

enough of this nonsense,
   richard
-- 
richard welty               welty@algol.crd.ge.com
518-387-6346, GE R&D, K1-5C39, Niskayuna, New York
   ``Quotes and commas and backquotes, oh my''

jlg@lanl.gov (Jim Giles) (05/09/89)

From article <905@twwells.uucp>, by bill@twwells.uucp (T. William Wells):
> In article <13113@lanl.gov> jlg@lanl.gov (Jim Giles) writes:
> :       if (cond1) {
> :          [...A...]   /* lots of code */
> :          goto LABEL;}
> :       else if (cond2) {
> : LABEL:   [...B...]   /* lots more code */
> :       }
> [...]
> :                                  Solution 2) imposes a code space penalty
> : as well as making code maintenance difficult (you must always remember to
> : update _both_ versions of 'B').
> 
> Only half true. Many (most?) optimizers will recognize that the two
> code sequences are identical and put the branch where you would
> expect.

There's a limit to what an optimizer can do.  Suppose the example were
a long sequence of "else if"s and that SEVERAL distinct branches all ended
with sequence B.  Or, suppose the long sequence of "else if"s contain
some branches that end with sequence B and others that end with C where
B and C are disjoint.  Duplicating the code can waste a _lot_ of space
and really make maintenance a nightmare!

> [...] 
> Be aware that a *single* goto in a function can cause many optimizers
> to do nothing for the function. The reason for this is that many of
> the better optimization techniques depend on the program having a
> particular control structure and transforming an arbitrary program
> into one that is acceptable is a hairy task.

This is _REALLY_ irritating though.  The example above obeys all the
"rules" of a well structured control construct: it has only one entry;
it has only one exit; it flows strictly from top to bottom of the page;
etc..  There _IS_ a language feature that allows this to be done with
an accepted "structured" mechanism.  I hesitate to mention it though,
since it is _much_ less readible than the version with GOTOs - it
was an "event driven" mechanism devised by Zahn (C.T. Zahn. "A Control
Statement for Natural Top-Down Structured Programming." Symp. on 
Programming Languages. Paris, 1974):

       begin quit on event1
          if (cond1) {
             [...A...]   /* lots of code */
             raise event1;}
          else if (cond2) {
             raise event1;
          }
       then
          event1: [...B...]    /* lots more code */
       end

In this case, the sequence between "begin" and "then" is executed once
(or until a named event arises).  If no even arises, the part between
"then" and "end" is simply skipped.  If a named event arises (they all
must be listed on the "begin" line and each must have a handler in the 
"then" part) the corresponding event handler is executed and the program
continues with whatever follows "end".  I don't like this as well as I do
GOTOs.

In the Nemesis programming language, the words "begin" and "end" have
no flow-control meaning.  They are instead used, entirely, to allow
local restrictions on scope.  So:

      Begin               ! exclamation point is comment marker
         Import all       ! bring in all outside declarations
         If (cond1) then
            ![...A...]      stands for lots of code
            Goto 1
         Else if (cond2) then
  1         continue      ! label may only appear on a no-op statement
            ![...B...]      stands for lots more code
         Endif
      End

This limits the scope on the statement label '1' in such a way that
it can't be jumped to from outside the begin-end block.  IMHO this
provides the correct level of control over how GOTO is used without
unduely constraining the programmer or obscuring the program.  Of
course, Nemesis doesn't _require_ that you limit the visability of
labels this way, nor does it restrict _where_ a label may occur.  But,
there's only so much hand-holding a language can provide.

les@chinet.chi.il.us (Leslie Mikesell) (05/09/89)

In article <4383@ttidca.TTI.COM> hollombe@ttidcb.tti.com (The Polymath) writes:

>Where the break goes is _very_ specific.  It gets you out of the innermost
>containing loop (or switch).  Where a goto goes is _anywhere_ it damn well
>wants to.  I'd much rather match up a few braces (which, in _my_ coding
>standard, are aligned vertically on the page) than search through thousands
>of lines of code for a goto label.  Not to mention finding such a label in
>the middle of a program and wondering how many goto statements go to it
>and where they are.

Who uses paper anymore?  Any editor worth loading can find all the references
to a label faster than you can determine if a "break" is inside of a
switch or not (assuming you were bright enough to make the label a unique
piece of text).  I wish someone would re-think programming languages in
the context of intelligent editors.  I would really like to see "named"
enclosing braces like this:
if (foo) {:foo-cond
  while (bar < 2) {:bar-loop
        do_something();
	bar++;
  }:bar-loop
}:foo-cond

where bar-loop and foo-cond are arbitrary and optional text that must
match at the start and end.  Ordinarily I don't like extra verbosity
but sometimes I get the feeling I'm in a maze of twisty {}'s, that
all look alike.  This would also allow a reasonable diagnostic from
lint or the compiler when a brace is misplaced.  Can't we forget about
the days of paper-tape and punch cards?

Les Mikesell

hollombe@ttidca.TTI.COM (The Polymath) (05/10/89)

In article <1745@wasatch.utah.edu> cetron@wasatch.utah.edu (Edward J Cetron) writes:
}	This entire GOTO debate seems to be indicative of the quality of 
}programmers currently available today.  To them, STRUCTURE is EVERYTHING.
}They've even forgotten (or never learned WHY structured concepts are good).
}But MOST IMPORTANTLY the forget that somewhere, somehow, a computer HAS to
}execute these programs. Before I ever was taught about programming, I was
}taught how the computers worked at the machine code level.  If once only
}considers the computer at the HLL level, no matter how good and optimizing
}compiler you have, you can still write stuff that is damned inefficient. 
}
} [ etc. in the above vein ]

When I'm concerned about machine efficiency, I write in assembler. (I've
written a _lot_ of assembler on some projects).  In my current
environment, I'm concerned about portability.

There are always tradeoffs.

-- 
The Polymath (aka: Jerry Hollombe, hollombe@ttidca.tti.com)  Illegitimati Nil
Citicorp(+)TTI                                                 Carborundum
3100 Ocean Park Blvd.   (213) 452-9191, x2483
Santa Monica, CA  90405 {csun|philabs|psivax}!ttidca!hollombe

hollombe@ttidca.TTI.COM (The Polymath) (05/10/89)

In article <1383@cygnet.CYGNETSYSTEMS> mark@cygnet.UUCP (Mark Quattrocchi) writes:
}In article <11136@bloom-beacon.MIT.EDU> jik@athena.mit.edu (Jonathan I. Kamens) writes:
}>In article <1814@ubu.warwick.UUCP> mirk@uk.ac.warwick.cs (Mike Taylor) writes:
}>>How many times have you seen this kind of code?
}>>
}>>	printf ("Enter your sex: ");
}>>	while (sex != "m" && sex != "f") {
}>>		gets (sex);
}>>		if  (sex != "m" && sex != "f")
}>>			printf ("<m> or <f> only: ");
}>>	}
}>
}>Indeed, this is a pretty bad example of where a goto would be useful,
}>because you are simply illustrating what the purpose of the C do ...
}>while construct is for:
}>
}>do {
}>   fprintf(stdout, "Enter your sex (<m> or <f> only): ");
}>   fflush(stdout);
}>   fgets(stdin, sex, 2);
}>   fflush(stdin);
}>} while ((*sex != 'm') && (*sex != 'f'));

}Speaking of jumping to conclusions, your code is not a one for one
}equivalent of the original. Even though I agree with your interpretation,
}you are cheating by combining the print statements together. Try again
}only don't cheat.

This isn't cheating.  Both code fragments accomplish the same function --
getting the user's sex.  The second fragment does it better on several
counts.  Not only is the code simpler, more efficient and easier to
maintain, but it helps prevent the end user from making an avoidable
error.

Human factors is part of programming.

-- 
The Polymath (aka: Jerry Hollombe, hollombe@ttidca.tti.com)  Illegitimati Nil
Citicorp(+)TTI                                                 Carborundum
3100 Ocean Park Blvd.   (213) 452-9191, x2483
Santa Monica, CA  90405 {csun|philabs|psivax}!ttidca!hollombe

geoff@cs.warwick.ac.uk (Geoff Rimmer) (05/10/89)

Here is my solution.  Which does the same as that of the original
poster, and in addition:

(a) it checks the buffer overflowing;
(b) it checks for EOF
(c) it is correct C code

-----------------------------------------------------------------------------
#include <stdio.h>

main()
{
	char str[4];
	printf("Enter your sex: ");
	do
	{
		fflush(stdin);
		if (!fgets(str,3,stdin)) exit(1);
	} while (*str!="m" && *str!="f") ? printf("m or f only: "):0);
	printf("sex is %c\n",*str);
}
-----------------------------------------------------------------------------

In the original poster's FOLLOWUP article, he writes:
> Equally invalid, (though correct) are the solutions posted by some
> people of the form:
> 
> 	printf (message1);
> 	while (gets (sex), (*sex != 'm' && *sex != 'f'))
> 		printf (message2);
> 
> This involves a C-specific construct (the comma operator that allows
> you to do lots of stuff between checks), which is one of the neat
> things about C, but does nothing to remove the difficulty of
> expressing some logic-routes in  generic structured contructs.

If you don't like these "neat tricks" as you call them, you are quite
free to go choose another language to program in.  However, the
implication of the original posting was that you were referring to C,
and that is why everyone has given answers in C.  The operators like
"," and "?:" are very useful, and you shouldn't complain at people for
using them because they are "C-Specific".  If you've got features, use em!

Geoff - "You can't beat the feeling"

	/---------------------------------------------------------------\
	|	GEOFF RIMMER  - Friend of COCA COLA CLASSIC		|
	|	email	: geoff@uk.ac.warwick.cs			|
	|	address : Computer Science Dept, Warwick University, 	|
	|		  Coventry, England.				|
	|	PHONE	: +44 203 692320 (9 lines)			|
	|	FAX	: +44 865 726753				|
	\---------------------------------------------------------------/

joe@logi-dc.UUCP (Joe Dzikiewicz) (05/11/89)

Talk about vampire debates!  Folks have been having flame wars on the GOTO
issue since before the net was born.  Can't we put a stake in the heart of
this issue and agree to disagree?

			yeesh,
			Joe Dzikiewicz

bill@twwells.uucp (T. William Wells) (05/11/89)

In article <13301@lanl.gov> jlg@lanl.gov (Jim Giles) writes:
: From article <905@twwells.uucp>, by bill@twwells.uucp (T. William Wells):
: > In article <13113@lanl.gov> jlg@lanl.gov (Jim Giles) writes:
: > :       if (cond1) {
: > :          [...A...]   /* lots of code */
: > :          goto LABEL;}
: > :       else if (cond2) {
: > : LABEL:   [...B...]   /* lots more code */
: > :       }
: > [...]
: > :                                  Solution 2) imposes a code space penalty
: > : as well as making code maintenance difficult (you must always remember to
: > : update _both_ versions of 'B').
: >
: > Only half true. Many (most?) optimizers will recognize that the two
: > code sequences are identical and put the branch where you would
: > expect.
:
: There's a limit to what an optimizer can do.  Suppose the example were
: a long sequence of "else if"s and that SEVERAL distinct branches all ended
: with sequence B.  Or, suppose the long sequence of "else if"s contain
: some branches that end with sequence B and others that end with C where
: B and C are disjoint.  Duplicating the code can waste a _lot_ of space
: and really make maintenance a nightmare!

What these optimizers do is to start from a point which several code
sequences end at and work backwards on all branches, munching
instructions so long as they are identical. So those are not really
problems. My own experience is that, while it is theoretically
possible to waste a lot space in this way, in practice it doesn't
happen.

The place where I've been most tempted to use a goto is, however,
very similar; had I succumbed, I'd have written code like:

	switch (n) {
	case 1:
		A;
		goto label;
	case 2:
		B;
label:
		C;
	}

So far, I've always found an acceptable way to avoid doing this.

: > Be aware that a *single* goto in a function can cause many optimizers
: > to do nothing for the function. The reason for this is that many of
: > the better optimization techniques depend on the program having a
: > particular control structure and transforming an arbitrary program
: > into one that is acceptable is a hairy task.
:
: This is _REALLY_ irritating though.  The example above obeys all the
: "rules" of a well structured control construct: it has only one entry;

Oh, I agree. That doesn't mean that these optimizers are smart enough
to recognize that it is so. The problem is that the code to do this
generally is hairy; however, writing code that handles enough of the
special cases is a real chore and there is no guarantee that one
really has done enough. Or so the reasoning goes.

---
Bill                            { uunet | novavax } !twwells!bill

jik@athena.mit.edu (Jonathan I. Kamens) (05/12/89)

In article <1860@ubu.warwick.UUCP> geoff@cs.warwick.ac.uk (Geoff
Rimmer) writes:

>Here is my solution.  Which does the same as that of the original
>poster, and in addition:
>
>(a) it checks the buffer overflowing;
>(b) it checks for EOF
>(c) it is correct C code

Actually, it is not correct C code for six reasons.  In fact, it
won't even compile.  It's not very intelligent in an argument like
this to be all high-and-mighty and post a code fragment that you
claim is "correct C code" when it won't even compile.

Here's the code you posted:

>#include <stdio.h>
>
>main()
>{
>	char str[4];
>	printf("Enter your sex: ");
>	do
>	{
>		fflush(stdin);
>		if (!fgets(str,3,stdin)) exit(1);
>	} while (*str!="m" && *str!="f") ? printf("m or f only: "):0);
>	printf("sex is %c\n",*str);
>}

1. You aren't flushing stdout after printing the prompt, and the
   prompt does not end in a newline, so in many operating systems the
   prompt will not be printed.
2. You flush stdin, but, to quote from the man page:
     Fflush causes any buffered data for the named output stream
     to be written to that file.  The stream remains open.
   In other words, fflush is not defined for input files, and stdin is
   input-only.
3. You assume that printf will return a non-zero value.  Now, I don't
   know about your implementation of printf, but mine (BSD 4.3)
   doesn't spec what printf returns, and I don't think that most
   implementations ahve such a specification (although I believe that
   ANSI says printf should return the number of characters it's
   printed).  In fact, I just compiled your program (with the two bugs
   below fixed, since it won't compile otherwise), and our IBM RT
   library seems to return 0 after a successful printf, so your code
   loses.
4. You're missing a parenthesis at the beginning of your while boolean
   expression.
5. You're comparing the value of a char to the value of a string
   pointer in your boolean expression.  It should be
     (*str!='m' && *str!='f')
   rather than what you have.
6. It doesn't print an error message if the fgets fails.  Now,
   granted, this isn't really "incorrect C," but rather "incorrect
   programming," but it should be pointed out nevertheless.

Oh, and one more thing: what the hell good is a program that does
nothing but get somebody's sex and print it? :-)

Jonathan Kamens			              USnail:
MIT Project Athena				410 Memorial Drive, No. 223F
jik@Athena.MIT.EDU				Cambridge, MA 02139-4318
Office: 617-253-4261			      Home: 617-225-8218

gateley@m2.csc.ti.com (John Gateley) (05/12/89)

I haven't seen anybody mention what I consider to be the most valid
use of goto: implementing new control structures. For languages without
coroutines, a sufficiently powerful goto can be used to implement them.
This is true for any new control structure.

John
gateley@tilde.csc.ti.com

gorpong@telxon.UUCP (Gordon C. Galligher) (05/12/89)

In article <1745@wasatch.utah.edu> cetron@wasatch.utah.edu (Edward J Cetron) 
  writes:
>	This entire GOTO debate seems to be indicative of the quality of 
>programmers currently available today.  To them, STRUCTURE is EVERYTHING.
>They've even forgotten (or never learned WHY structured concepts are good).
>But MOST IMPORTANTLY the forget that somewhere, somehow, a computer HAS to
>execute these programs. 

[...deleted Edward's personal history...]

>I would
>rather have a clearly written program (structured or not) which accomplishes
>what the PROGRAM is intended to do, without excess baggage and }'s JUST to

So you really don't care if anyone else can read this code to manage it?  
Believe it or not, but 80% of all code is in the maintenance stage (that's when
it is either being modified to add new features, fix bugs, whatever), and if
it was written to do just ONE task, who cares about how it looks, but it does
the job, then you might as well advocate just throwing the program out and
rewrite it to do the new tasks because it would be faster to do that  than to
try to read the code that the person wrote.  The whole thing about writing
re-usable code is to make it READ well.  That's why most people are going to
higher level languages for most things (I agree that for speed, assembly is
probably the best choice, but if kept to a minimum) because higher level 
languages (if written "correctly") are easier to maintain.  (The 'correctly'
is an extremely subjective word and by that I mean written with the knowledge
that you may not live forever and someone, someday will have to try to figure
out what your code does!

>	Maybe that's why I only hire hardware oriented people.  You can teach
>a h/w person to program, but most s/w types are confused by hardware.

I'm not going to TOUCH this!! :-).

>	Sorry for the flame, I'm just tired of interviewing smug new CS
>students who know nothing about reality and using the right tools for the
>job.  They make great followers, but we desparately need thinkers and leaders.

Have you ever thought about trying to HELP these "smug new CS students" by
giving them some of your ideas, or are you too tied up trying to rewrite soft-
ware you want to reuse? :-)

		-- Gordon.
		
-- 
Gordon C. Galligher  <|> ...!uunet!telxon!gorpong <|> gorpong@teleng.uucp.uu.net
Telxon Corporation   <|> "Captain, I hardly believe that insults are within your
Akron, Ohio, 44313   <|> prerogative as my commanding officer" - Spock
(216) 867-3700 (3512)<|>   (City on the Edge of Forever (Starring Joan Collins))

stephen@ziebmef.uucp (Stephen M. Dunn) (05/14/89)

In article <2848@cps3xx.UUCP> rang@cpswh.cps.msu.edu (Anton Rang) writes:
$In article <1814@ubu.warwick.UUCP> mirk@warwick.UUCP (Mike Taylor) writes:
$   [ ... ]  Listen, just 'cause Quiche-eater Wirth connected GOTOs with
$					     ^^^^^
$   lack of structure generally, doesn't mean either that (A) ALL use of
$   GOTO is unstructured and obfuscatory, or that (B) ALL obfuscated code
$   is due to use of GOTO -- so why is it that so many people seem to
$   believe these myths?
$It was Dijsktra [sp?].  Other than that, I perfectly agree!
   Dijkstra ... close but no carcinogenic cylinder.

   The statement above is quite correct IMHO.  However, in a language
like many dialects of BASIC which have no control structures other than
FOR-NEXT, GOTO and GOSUB, it _can_ be next to impossible to write anything
other than obfuscated spaghetti code.  Note that this does not contradict
either of the above points.  Also, it is possible to write some very
lousy code in languages which do not provide a GOTO (or, in those that
do, by avoiding it), especially if they provide no means for prematurely
terminating or repeating a loop other than a huge IF statement.  And, of
course, we all know it's possible to write very cryptic code in C, but
that doesn't mean that C should be abolished (it just means that programmers
should be taught not to write such code).

   Still, IMHO (for the second time) the use of GOTOs should be
minimized whenever possible, since it generally does lead to harder-to-
read programs which are unmaintainable by anyone other than the programmer
(and often not even maintainable by him/her more than a couple of weeks
later)!

-- 
-------------------------------------------------------------------------------
! Stephen M. Dunn              stephen@ziebmef.UUCP ! DISCLAIMER:  Who'd ever !
! Take off to the Great White North eh, ya hosehead ! claim such dumb ideas?  !
-------------------------------------------------------------------------------

cetron@wasatch.utah.edu (Edward J Cetron) (05/15/89)

In article <4396@ttidca.TTI.COM> hollombe@ttidcb.tti.com (The Polymath) writes:
-In article cetron@wasatch.utah.edu (Edward J Cetron) writes:
-}	This entire GOTO debate seems to be indicative of the quality of 
-}programmers currently available today.  To them, STRUCTURE is EVERYTHING.
-When I'm concerned about machine efficiency, I write in assembler. (I've
-written a _lot_ of assembler on some projects).  In my current
-environment, I'm concerned about portability.
-
-There are always tradeoffs.

	My point exactly - there are ALWAYS tradeoffs, but unless you have
been trained/educated to realize that there are tradeoffs (and then to
understand how to evaluate them), you have missed the boat.

-ed cetron
cetron@wasatch.utah.edu

cetron@wasatch.utah.edu (Edward J Cetron) (05/15/89)

In article <46@telxon.UUCP> gorpong@telxon.UUCP (Gordon C. Galligher) writes:
>In article <1745@wasatch.utah.edu> cetron@wasatch.utah.edu (Edward J Cetron) 
<  writes:
<<	This entire GOTO debate seems to be indicative of the quality of 
<<programmers currently available today.  To them, STRUCTURE is EVERYTHING.
<<They've even forgotten (or never learned WHY structured concepts are good).
<<But MOST IMPORTANTLY the forget that somewhere, somehow, a computer HAS to
<<execute these programs. 
<<I would
<<rather have a clearly written program (structured or not) which accomplishes
<<what the PROGRAM is intended to do, without excess baggage and }'s JUST to
<
<So you really don't care if anyone else can read this code to manage it?  

Didn't I say clearly written? Maintainable code can be written which DOES NOT
have lots of {}'s with no purpose but to meet some example of structured
programming style, not for clarity.

<Believe it or not, but 80% of all code is in the maintenance stage ...
<...the job, then you might as well advocate just throwing the program out and
<rewrite it to do the new tasks because it would be faster to do that  than to
<try to read the code that the person wrote.

I realize that maintainabilty is important, but the type who uses structured
techniques for the sole purpose of using them is likely to also to write code
which is poorly maintainable for other reasons. 

<<	Maybe that's why I only hire hardware oriented people.  You can teach
<<a h/w person to program, but most s/w types are confused by hardware.
<
<I'm not going to TOUCH this!! :-).

Teaching s/w is an exercise is logic, organization, problem solving etc...
Most students have background in these concepts h/w or s/w.  Teaching hardware
usually requires a more involved background in some EE, etc....  I didn't say
that the s/w are any less intelligent, just less knowledgeable.

<
<<	Sorry for the flame, I'm just tired of interviewing smug new CS
<<students who know nothing about reality and using the right tools for the
<<job.  They make great followers, but we desparately need thinkers and leaders.
<
<Have you ever thought about trying to HELP these "smug new CS students" by
<giving them some of your ideas, or are you too tied up trying to rewrite soft-
<ware you want to reuse? :-)

No, between teaching, lecturing, assisting new students, managing a software
team to 'do it write', and taking on the brain-damaged instructors who created
these students, I don't even get to write much code at all anymore.  Besides,
I much prefer recycled software to re-used software :-)

-ed cetron
cetron@wasatch.utah.edu

darin@nova.laic.uucp (Darin Johnson) (05/17/89)

>   Still, IMHO (for the second time) the use of GOTOs should be
>minimized whenever possible, since it generally does lead to harder-to-
>read programs which are unmaintainable by anyone other than the programmer
>(and often not even maintainable by him/her more than a couple of weeks
>later)!

Another point.  GOTO's don't get along well with optimizers.  Either the
optimizer gives up on some optimizations, or it spends lots of extra
time.  Of course, in C, a break or continue cause the same problems to
a lesser degree.  Optimizers can usually do more with languages like
Pascal and ADA, because loops are easily recognized, a FOR statement
isn't shorthand for a WHILE statement, etc.

Darin Johnson (leadsv!laic!darin@pyramid.pyramid.com)
	We now return you to your regularly scheduled program.

mike@arizona.edu (Mike Coffin) (05/17/89)

From article <554@laic.UUCP>, by darin@nova.laic.uucp (Darin Johnson):
> Another point.  GOTO's don't get along well with optimizers.  Either
> the optimizer gives up on some optimizations, or it spends lots of
> extra time.

There is no reason that gotos should cause problems for a compiler,
unless the programmer uses them to produce irreducible flow graphs.
In particular, using gotos to break out of nested loops should not
cause problems.  If the mere presence of a goto causes the the
compiler to give up, it isn't much of a compiler.

> Of course, in C, a break or continue cause the same problems to
> a lesser degree.

Break and continue do not create irreducible flow graphs.

> Optimizers can usually do more with languages like Pascal and ADA,
> because loops are easily recognized, a FOR statement isn't shorthand
> for a WHILE statement, etc.

Modern optimizing compilers generally turn everything into a graph of
basic blocks almost immediately.  The optimizations depend on the
topology of the resulting graph, not where it came from.  In
particular, the standard algorithms for data-flow analysis require the
graph to be reducible, so may compilers punt if they are given an
irreducible flow graph.  See any of the standard compiler books for
details.
-- 
Mike Coffin				mike@arizona.edu
Univ. of Ariz. Dept. of Comp. Sci.	{allegra,cmcl2}!arizona!mike
Tucson, AZ  85721			(602)621-2858

kay@warwick.UUCP (Kay Dekker) (05/18/89)

You know, if I'd had any idea that people would start a "Tis/Tisnt" over
GOTO, I wouldn't have posted the original article.  More heat, less light.
I can't wait for the pro/anti debate to become as futile as the (proverbial)
angels on the head of the pin.  Sigh.

Kay




the Crisco Kid: nasty pinko faggot agnostic pervert punk.  csx043@uk.ac.cov.cck

bill@twwells.uucp (T. William Wells) (05/19/89)

In article <77467@ti-csl.csc.ti.com> gateley@m2.UUCP (John Gateley) writes:
: I haven't seen anybody mention what I consider to be the most valid
: use of goto: implementing new control structures. For languages without
: coroutines, a sufficiently powerful goto can be used to implement them.
: This is true for any new control structure.

It does seem that the memory of the net gets shorter all the time. I
reposted the enclosed article less than two weeks ago, and the GOTO
flamers are *still* acting if the words were never said. (For those
whose memory isn't that short, yes I've updated the article a little.)

===

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

I say this, having managed (and written huge chunks of) a 17,000 line
software system (and that is only the part we sell, and does not
include development tools). I've developed several other software
systems, each involving many thousands of lines of C code. I have
programmed in C for seven years now and have NEVER used a goto. We
have uncounted megabytes of C code written in-house. None of it
contains a goto.

With that aside, let me explain why the goto discussion is really
fruitless. 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 WRONG WITH GOTO. (And how do I reconcile with my
mouthing off above? Wait and see...) The thing that is screwed up is
the control structures being implemented with the gotos.

One whole point of the structured programming debate 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 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 obvious.

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

The second question should be: given a particular language, how
should the control structures be implemented?

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 them. 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. 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: I have chosen a set of control
structures which is appropriate to programming in C, for the kind of
programming tasks that I do. It happens that, while my set of control
structures includes multi-level breaks and continues (which could be
implemented with a goto), I have never had need to implement one with
a goto. Given the amount of code I write, it seems to me that one
might never need to use an explicit goto in C code.

There is 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. You can 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. I normally code it as:

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

However, this is not the most efficient way to do it. 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 this
was all you did with goto, I don't really see any reason why not (but
I do think your program should include a comment saying that you use
goto for state machines and describes how you structure it). 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 structure your goto belongs to.

---
Bill                            { uunet | novavax } !twwells!bill

kannan@babcock.cerc.wvu.wvnet.edu (R. Kannan) (05/28/89)

From article <1814@ubu.warwick.UUCP>, by mirk@warwick.UUCP (Mike Taylor):
> In article <3, I think> gould@rosemary.cs.reading.ac.uk (Adrian Gould) writes:
>> Lets eradicate the GOTO from all languages.
> 
> I hate it when people say things like that; As if you can just wave a
> magic wand over a language by excising GOTO, and everything will be
> alright.  Listen, just 'cause Quiche-eater Wirth connected GOTOs with

> Mike Taylor - {Christ,M{athemat,us}ic}ian ...  Email to: mirk@uk.ac.warwick.cs
> Unkle Mirk sez: "G G7/B C F G G7/B B7 Em; Dm7 G7/B C Gdim7 G D C Gdim7 G D Cm"
Dear Dr. Mike Taylor,
I agree 100% that GOTO has been subject to very unfair criticism. The 
example you have given, does good. But your comparison with Ada
exception handling feature really is completely out of line.

	Can you clarify further, why Ada exception handling should be
considered just as another glorified GOTO package.

Please educate me in this regard.

--kannan

mirk@warwick.UUCP (Mike Taylor) (06/02/89)

In article <chicken> kannan@babcock.cerc.wvu.wvnet.edu (R. Kannan) writes:
> I agree 100% that GOTO has been subject to very unfair criticism.
> The example you have given, does good. But your comparison with Ada
> exception handling feature really is completely out of line.  Can you
> clarify further, why Ada exception handling should be considered just
> as another glorified GOTO package.

Well, you've got to stand back from the glorious DoD fanfare, (or is
it MoD?), and look at what the language really has to offer.  Like
IBM's PC, once you take away the badge, nothing much.  It's the only
language I know that has only ONE control-structure; unconditional
GOTO.  I mean, OK, dress it up a bit, represent it by a right-pointing
arrow, whatever, but at the end of the day, they're not fooling
anyone, and I know GOTO when I see it!

Oh dear, I'm terribly sorry, I've just realised I'm talking about APL,
not ADA  :-) :-) :-)

Seriously though, ask yourself, what IS exception handling?  It's just
saying, "When event E occurs, go to code section C, whatever else
you're doing".  S'a lot like catching signals in C.  All that frogging
about with setjmp() and longjmp() gets represented as something
clever, something for "real programmers", and most people seem to
swallow the idea without flinching, and more importantly, _without_
_THINKING!_  This is what I really object to, I guess.

I mean, C is much more my field that ADA, so don't get the impression
that I really know what I'm talking about (1/2 :-), but certainly I
have come across the sort of attitude a lot of the while that says
that once you dress GOTO up a bit, call it something different,
(longjmp() in this case), everything is OK.

I hope that everyone reading this knows deep down inside that it is
just as possible to abuse "while", "for", "do", "longjmp()" or
whatever other control structure you use, as it is to abuse GOTO.  It
is _easier_ to abuse GOTO, partly because many of us learned our
programming on machines where that was all we had.  But at the end of
the day, control structures are supposed to be tools, and if we're
irrationally afraid of one of them, then it's not gonna help us.

	"All [control structures] are permissible to me --
	 But I will not allow myself to be mastered by any!"
		-- Apostle Paul, 1 Corinthians

On an only vaguely related note -- the one thing that annoys me about
C is that you can't do n-level breaks.  If Bourne shell (:-P) can
manage it, I'da hoped C could!
______________________________________________________________________________
Mike Taylor - {Christ,M{athemat,us}ic}ian ...  Email to: mirk@uk.ac.warwick.cs
"istrcmp() -- Naughty but nice! ...  Why isn't my program working?" - Sunny