Why should GOTO be avoided?
IDL's GOTO statement is a control statement that is used to jump to a specific point in the code. It is similar to "goto" in C++ and many other languages. "How convenient!" you might say. "A quick, easy way to jump to a desired section code if certain conditions are met."
Not so fast.
Most programmers will tell you that the GOTO statement should be avoided. In fact, IDL's own documentation advises against it. Actually, it doesn't advise against it; it outright states that using it is bad programming:
"The GOTO statement is generally considered to be a poor programming practice that leads to unwieldy programs. Its use should be avoided."
Why should GOTO be avoided?
Now that we know that GOTO is maybe not such a great thing, let's look at a couple of reasons why GOTO should be avoided. This is certainly not an exhaustive list.
Code can get confusing very quickly when it takes arbitrary paths and jumps from place to place. The more GOTOs in the same routine, the worse it gets. Debugging is enough of a challenge when code runs sequentially. When it jumps around as you are trying to step through it, debugging can become a nightmare.
It is easy to get caught in an infinite loop if the goto point is above the goto call. This is almost guaranteed if there is no reliable escape from the code, such as a RETURN statement within a conditional statement.
Danger of using GOTO within a catch block
It might be tempting to put a goto statement within a catch block. If there is an error, catch it, and then jump to a certain section of code that performs some recovery action, right?
The problem with this is that if you don't cancel your catch and an error occurs later down the road after the goto point, it will be re-caught by the catch statement, and then you have the infinite loop problem again (hint: always cancel your catch before performing recovery action). If you do cancel the catch, however, then you've just cancelled the handler for your mainline code, and then you jump right back into it. Additional errors will not be handled. Unless you have a different catch block somewhere in the routine, or maybe one somewhere at a higher scope level. When that happens, good luck debugging (see "Confusing Code" above).
A catch block should usually perform a recovery and then return out of the routine rather than try to jump somewhere else in the routine.
Alternatives to GOTO
In addition to the examples above, there are a handful of scenarios where using GOTO might sound like the best or easiest thing to do. The good news is that in programming there is almost always more than one way to do the same thing, so there is a good chance that there is an alternative to using GOTO.
The BREAK statement is an easy way to immediately exit a loop. Unfortunately, though, it only exits the current loop, which isn't helpful in the case where you have multiple loops nested within each other. This is what it looks like with and without a goto. Note that the second example contains a special flag, just to indicate that you need to break from each loop.
A better solution: Why not just move the looping code into its own subroutine? You may need to pass a handful of arguments, such as the contents of the loop, but it makes the code simpler. Now, to exit the loops, simply return from the subroutine.
Automatic Garbage Collection
A common use of GOTO is to perform a "common exit," or in other words always call a certain section of code before returning from a routine. Perhaps this is done to reset a variable or to close any file units opened in the routine. Maybe it does some other kind of cleanup before returning from the routine.
An option for how to not only perform common cleanup after exiting, but to guarantee that the cleanup will always be done is to create an "in-scope" object, which is cleaned up by IDL's automatic garbage collection.
Basically, the idea is to put any cleanup code in a temporary object's ::Cleanup method. When exiting the routine, the object falls out of scope, and once the object falls out of scope, IDL will automatically destroy, or "garbage collect," the object. When doing so, the Cleanup method automatically gets called. I wrote an IDL Data Point blog post last year describing the in-scope object, which can be found here.
Are there any good times to use GOTO?
Over time, I've learned one thing about rules of programming - they are meant to be broken, but when you break them, do so carefully.
Occasionally, using a goto statement really is the easiest thing to do, such as if you want to quickly jump over code or perform a multi-way split. Sometimes you want to simply trade off the "don't use goto" rule of thumb with convenience, and doing so can be a matter of personal preference. It's true that using goto often results in fewer lines of code to write compared to other types of logic that would provide the equivalent functionality.
The bottom line is that although goto can almost always be replaced by other forms of logic, it still exists today and is legitimate IDL syntax. There are quite a few hazards to it, but when used sparingly and with care, it can be a useful tool.