I used GOTO!

i haven’t used a goto statement since that last time i wrote a .bat file - which would have been for the front door of a bbs system in the early 90s

Small Clanger’s immortal soul is finally within my grasp. Soon the stars will right…

If you don’t want a big list of OR’s because they don’t conceptually hang together could you not do somrhing like:

do_audit := FALSE

IF a_common_event // we expect this to happen a lot
do_audit := TRUE
ELSE;

IF rare_event1
OR rare_event2
OR rare_event3
OR . . . an enormously long list of rare_events

do_audit := TRUE
END IF

<<write_audit>>
IF do_audit THEN
do_audit_stuff()
END IF

Aaaargh - keyboard malfunction submitted before I was read.

Missed out an END I believe.

A jump/GOTO instruction is absolutely necessary at the assembly language level (which itself was the first “abstraction” from actual poking of bits to form machine instruction code). As newer programming languages became yet more structured and abstract, GOTO was “grandfathered in” since so many programmers already were trained in its use.

Nowadays, except in the case of exception handling constructs in a language which does not explicitly support them, use of a GOTO statement can be avoided. And as we (professional programmers and software engineers) are taught in school, MUST be avoided.

So why should it be avoided? Because over time, software maintenance is far costlier than software development.

Use of GOTO may be considered “simplier” or “easier” for a developer to hack out code quickly and get it to do what he wants… Which is fine for toy programs or small utilities. But for application programming that will (a) have a large code base, (b) exist for a long time, and © will have many people different working on it over that time, the following good software practices they teach you about in school really pay off.

I work at a firm with a VERY large code base in C and C++. Some of the core routines for critical applications are 15 years old. Figuring out code involving GOTO jumps is fortunately not among our challenges; however, we are certainly plagued by other similar “bad programming” practices that are preached against in school:

[ul]
[li]Uncommented code with very unclear variable names and constructs (e.g. a loop that iterates over something called funds_list and fiddles with something called fund_list, which have different scopes).[/li][li]Worse, comments that clearly no longer apply to the code in question.[/li][li]5±year-old comments like “TODO”, “to be retired” or “short-term fix”, or my favorite, “BAD” or “No!!!” (real comments I have seen), which flag some code as potentially suspicious but with no indication as to why.[/li][li]Lots of global variables and structures all over the place that get initialized and maintained in different functions in different files, resulting in…[/li][li]Functions that only work when other functions/structures have first been called or set up, for no obvious reason (reliance on “side effects”).[/li][li]Huge chunks of code written inside large if/else blocks instead of moving them to subroutines/separate functions with sensible names. And since nobody knows exactly what it is meant to do, nobody dares to move it around.[/li][li]Lots of occurences of “magic values”, hard-coded constants representing behavior like “if (rpt_type==14) { [lots of code about handling spread-priced marksheets] }”…[/li][/ul]

I could go on, but would risk hijacking this thread into the BBQ Pit.

So, if you always wondered “just how bad can it be to use GOTO, global variables, magic values, run-on code blocks, etc.” – well, I can’t speak for GOTO, but the others are royal pains in the asses to work with.

As a programmer, in any language, always code with the idea that someone else will be coming to your code for the first time – how would they feel reading it? And realize that often, that person will be YOU revisiting the code 2 or 3 years later and not remembering a damn thing about what you were trying to do before.

For more insight on why it’s a good idea to Be A Good Programmer, I highly recommend the book The Practice of Programming by Kernighan & Pike. I don’t know if this or a similar book is a standard text for CS courses nowadays, but it should be. (They’re better known for being the authors of The Unix Programming Environment, but the book is not language-specific.)

Also informative and entertaining is the book Anti-Patterns, which models itself on the popular book on Software Patterns but addresses how to categorize and fix common problems in large-scale programming.

For that matter, anybody involved in designing or managing a large-scale system in C++ specifically would do well to read Large Scale C++ Software Design.

I’ve been a professional game developer for 10+ years, and game development is noted for being a lot more casual and just-make-it-work than other fields of development (with some justification, as if our code crashes, no one dies, there are no power grid failures, etc.). There is only one time I can absolutely clearly remember using GOTOs, which was in an inner graphics loop that had to be as optimized as possible, which was basically a FSM. Normally, I would write it as:



do
{
  switch(eState)
  {
  case STATE_FOO:
     ...
     if (something)
     {
        eState = STATE_BAR;
     }
     else
     {
        eState = STATE_WACK;
     }
     break;

  case STATE_BAR:
    ...
    break;
  case STATE_WACK:
    ...
    break;

    ...
   }
}
while (eState != STATE_DONE);


or words to that effect. However, as this was a very small and tight loop, I didn’t want all the extra overhead of doing all the switch commands. So I basically replaced “case” with “label” and “eState =” with goto. However, that was a pretty unusual case, and one that really ought to have been recoded in assembler.

One other situation in which GOTO strikes me as fine is something where you’re searching through various for loops for some condition to be true, at which point, if it’s true, you do something and stop looping, and if it’s never found, you do something else.

With GOTO, you get this:



for (x=0;x < 4; x++)
{
   for (y=0;y <4; y++)
   {
      if (check(x,y))
      {
         doSomething(x,y);

         GOTO found;
       }
   }
}

DoSomethingElse();
found:


which is basically maximally efficient, algorithmically, and is not particularly unreadable.
Without GOTO, you need to do something like this:



bool bFound = false;

for (x=0;x < 4; x++)
{
   for (y=0;y <4; y++)
   {
      if (check(x,y))
      {
         doSomething(x,y);
         bFound = true;
         break;
      }
   }

   if (bFound)
   {
      break;
   }
}

if (!bFound)
{  
  doSomethingElse();
}


I Am Not A Programmer! I have written good code, though. A fellow-student of mine, back in 1978 or so, had a summer job dealing with bad code. A department store was going to rewrite their whole accounting/payroll/inventory system in COBOL, and thought it would be good to know first what exactly the current program was doing. So my friend was put in a room with an IBM360 assembly-language manual, a listing of the program, and a big box of multi-coloured pens. In the fall she came back looking drawn and tired, and explained that the original code had been written by the guy who used to fix the cash registers. Then after a while he went back to the cash registers, and it seemed like everybody who walked through the store after that had hacked on the code.

GOTO was the least of her problems. Most of the code was uncommented, or the comments were like those mentioned by robardin. She found code that repeated the same action twice, that did something and immediately undid it, and code that was jumped around or commented out.

But she got it figured out!

What’s wrong with that? Maybe I’m just used to it, but I find this as much or more readable/understandable than the GOTO version.

And really, the most readable approach would be one that put the whole bit of code that is doing the lookup in some sensibly subroutine like “findThing()” and just have code that goes:



if (findThing())
  doWhatHappensIfThingIsFound();
else
  doSomethingElse();



PS - A minor side pet peeve, but I detest so-called “Hungarian notation” for variables like “bFound”. I find all the type-prefixing annotation just so much clutter. Isn’t a name like “found” already clear enough? And what happens if you change a variable’s type, like changing a customer_id field from integer to string?

Frankly it’s not even clear to me why someone would want to know the type of a variable throughout the code; most variables are local, and what really matters from a design perspective are the type declarations for functions and interfaces. The compiler will catch it if you try to use a function with the wrong types of arguments.

Ultimately though, what’s more important for maintenance is consistency of a coding style. If I took a(nother) job at a shop where Hungarian Notation was the standard, I would… comply. (Or more likely at this point in my career, pass on the job :))

I’d just do this:



if (testForEvent() == true)
{
  do_audit_stuff()
}

function testForEvent()
{
  boolean eventFound=false;

  if (common_event)
  {
    eventFound = true;
  }
  else 
  {
     if (uncommonEvents)
       eventFound = true;
  }
  
  return eventFound;
}


If your code has to be so tight that you can’t accept the overhead of a function call, then put it all inline.

If you wanted to do a big long series of tests, and don’t want to do a big OR type structure, you can do this:



  if (testforCommonEvent)
    eventFound = true;

  if (!eventFound && testForUncommonEvent1)
    eventFound = true;

  if (!eventFound && testForUncommonEvent2)
    eventFound = true;


With modern compilers each of the tests will short-circuit if the !eventfound boolean fails, and the second test won’t be executed. So in terms of overhead, what happens is that all the tests execute until one passes, and the subsequent code is just a bunch of tests on a boolean.

If you really don’t want that overhead, you can do this:



boolean testforEvents()
{
  if (testforCommonEvent)
    return true;   

  if (testForUncommonEvent1)
     return true;

  if (testForUncommonEvent2)
    return true;

  return false;
}


Although it’s generally bad practice to have multiple exit points from the same function, this is a fairly common violation of that rule.

You see similar constructs all the time in code where one section has to pass for the next section to execute properly.

I program in Java, C++, C#, VBScript, Javascript, and a couple of other languages. I can’t remember the last time I used a GOTO. Probably at least five years. My take is that if you find yourself coded into a corner where you think you absolutely have to use a GOTO, it’s time to look at your algorithm again and see if it can’t be written a better way.

10 Sin
20 GOTO Hell

All of y’alls examples are excellent and make perfect sense.

My take is that if it can’t, why go around in circles to avoid it?

Perhaps now would be a good time to mention that my company still has a few COBOL clients.

Hey, if you have to use one, you have to use one. I’m just saying that it’s often a symptom that you could have done a better job with the algorithm. Sometimes taking a step back and just thinking about what you’re trying to accomplish will give you an insight into a more elegant solution.

But some languages are pretty impossible use to without using GOTO. The early BASIC languages required the use of GOTO. There were no subroutines. It was just all linear code, and you could use labels and goto’s to control program execution. Man, that stuff was fun to debug.

I never understood the hatred of GOTO either. Most times it’s just an alternate way of doing the same damn thing. It doesn’t natively make things more difficult to read, we are just not as used to doing it. I have occasionally thrown a GOTO in just for it’s eye-cattching quality. Some times you just end up with a piece of code that is hard to eye read, and the subroutine, or function call seems to get glanced past by everyone reading it. The GOTO jumps out at people and says “Hey guys there is something happening on this line, pay attention to it, and don’t skip over it.”

Yes, it does make code harder to read. It also makes it harder to debug, and harder to modify and reuse. Obviously not in the simplest of examples, but widespread use of GOTO can lead to absolutely horrendous code. Like this:



function doSomething()
{
  for (i = x; i < y; i++)
  {
    innerlabel1:
    if (testForSomething(i))
      goto label1;
    else 
       goto label2;
    :innerlabel2
       process(i);
   }

  goto finish;
:label1
   if (another test)
     y = y + z:
:label2
    y = y + z/2;
    if (test3)
      i = i /2;
      goto innerlabel1;
    else
      goto innerlabel2;
:finish
}


Throw in a few hundred lines in between that stuff, and maybe a recursive call back to the same function, and let me know how debugging it works for you when process() throws an exception. And wait 'till you have more fun when you have to refactor this code a few years down the road to add some functionality. The odds of introducing bugs will be much higher when you have code jumping all over the place based on various conditions. Eventually, this kind of code just becomes completely unmaintainable.

Or think of it this way: In a properly structured program, you can break down chunks of the code and understand what they are doing. This little bit does this. This function achieves that. This object behaves this way. You can approach understanding the code in a segemented, modular fashion. In code littered with GOTOS, you can’t do that. Every part depends on something happening in another part. Program execution is labyrinthine. Consider code like this:



:label1
  Dosomething1()
:label2
  DoSomething2()
:label3
  DoSomething3()


When doSomething3 is called, can you count on Dosomething2 having been called? Nope. It depends where in code you branched from. If code branches to label1, then all three get executed. If it branches to label3, then it doesn’t. Just looking at this code by itself tells you nothing about how the program is going to behave. Instead, you have to go looking elsewhere to see where all the jumps to the labels are. And if that code in turn gets executed in different ways depending on other gotos, it rapidly becomes a nightmare.

Perhaps in another section of the code I have this:



:labelA
  if (testsomething1())
    goto label1
  if (testsomething2()) 
   goto labelC
:labelB
   if (testSomething3())
     gotoLabel2
   else
     gotoLabel3
:labelC
  if (testSomething4())
    goto Label3
  else 
    gotoLabelA


Following the execution path of this code is damned near impossible. And it’s trivially easy to accidentally insert nasty bugs. And since every part of this code depends on every other part, you can’t easily tear out a small useful part to reuse elsewhere.

Granted, these are extreme examples. But not that extreme. Because you’d be surprised how fast the use of GOTOs begets the use of more GOTOs. Look at code that’s been in service for 10 years and modified half a dozen times, and it can become a total maze. Then you get a bug that throws an exception only once every few days based on some obscure condition, and you have to try and follow the execution path to figure out what might be going on. Yuck.

Now, other constructs such as break, if/then/else and case switches are really just GOTOS wrapped up in more structured syntax, but they are self-limiting and self documenting. You can make some god-awful code with them too, but it’s much easier to stay out of the weeds.

Dude! My GOTO 409 with trips would have sucked your Trans Am up the tailpipes. :stuck_out_tongue:

As for the rest of this thread, it’s impossible for me to grasp the concept that of the roughly 35 responses to the OP, at least 30 posters know what he’s talking about.
I fear that, in this stage of my life, I’ve fallen into the company of weirdos.

mr. bus guy, lets go pick up a six-pack and see if anybody’s runnin’ out at the old abandoned airport this afternoon…

Building a raft is just an alternate way of getting across the ocean. However, other methods are more elegant, more reliable and more easily improved upon.

Comments have the same effect and they’re far easier to maintain.

You think so? I once worked on a program that was written in 1968 using GO TO and ALTER * that was nearly an exemplar of structured logic. Of course, I worked on it in 1983 when it was no longer maintainable and they were thinking of writing an entirely new system as the cheaper alternative to trying to debug the program.

I have never encountered a program using GO TO that was more than a year old that had not been corrupted by later modifications because the GO TO logic could not always be followed by every coder that opened it. Certainly, a superb program may be written with GO TO logic; I flatly deny that a program can be maintained if it contains GO TO logic–not because no programmer can follow it, but because no shop can guarantee that all their programmers are that good.

  • I had one boss whose unalterable dictum was that if he found a programmer using the ALTER, he would sacrifice him upon it.

So does an IF… THEN statement, or a WHILE construct, or a FOR loop, or any of the other alternatives to using GOTO. GOTO simply offers no advantage in that regard.