I've long been under the impression that goto
should never be used if possible. While perusing libavcodec (which is written in C) the other day, I noticed multiple uses of it. Is it ever advantageous to use goto
in a language that supports loops and functions? If so, why?
Everybody who is anti-goto
cites, directly or indirectly, Edsger Dijkstra's GoTo Considered Harmful article to substantiate their position. Too bad Dijkstra's article has virtually nothing to do with the way goto
statements are used these days and thus what the article says has little to no applicability to the modern programming scene. The goto
-less meme verges now on a religion, right down to its scriptures dictated from on high, its high priests and the shunning (or worse) of perceived heretics.
Let's put Dijkstra's paper into context to shed a little light on the subject.
When Dijkstra wrote his paper the popular languages of the time were unstructured procedural ones like BASIC, FORTRAN (the earlier dialects) and various assembly languages. It was quite common for people using the higher-level languages to jump all over their code base in twisted, contorted threads of execution that gave rise to the term "spaghetti code". You can see this by hopping on over to the classic Trek game written by Mike Mayfield and trying to figure out how things work. Take a few moments to look that over.
THIS is "the unbridled use of the go to statement" that Dijkstra was railing against in his paper in 1968. THIS is the environment he lived in that led him to write that paper. The ability to jump anywhere you like in your code at any point you liked was what he was criticising and demanding be stopped. Comparing that to the anaemic powers of goto
in C or other such more modern languages is simply risible.
I can already hear the raised chants of the cultists as they face the heretic. "But," they will chant, "you can make code very difficult to read with goto
in C." Oh yeah? You can make code very difficult to read without goto
as well. Like this one:
#define _ -F<00||--F-OO--;
int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO()
{
_-_-_-_
_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_
_-_-_-_
}
Not a goto
in sight, so it must be easy to read, right? Or how about this one:
a[900]; b;c;d=1 ;e=1;f; g;h;O; main(k,
l)char* *l;{g= atoi(* ++l); for(k=
0;k*k< g;b=k ++>>1) ;for(h= 0;h*h<=
g;++h); --h;c=( (h+=g>h *(h+1)) -1)>>1;
while(d <=g){ ++O;for (f=0;f< O&&d<=g
;++f)a[ b<<5|c] =d++,b+= e;for( f=0;f<O
&&d<=g; ++f)a[b <<5|c]= d++,c+= e;e= -e
;}for(c =0;c<h; ++c){ for(b=0 ;b<k;++
b){if(b <k/2)a[ b<<5|c] ^=a[(k -(b+1))
<<5|c]^= a[b<<5 |c]^=a[ (k-(b+1 ))<<5|c]
;printf( a[b<<5|c ]?"%-4d" :" " ,a[b<<5
|c]);} putchar( '\n');}} /*Mike Laman*/
No goto
there either. It must therefore be readable.
What's my point with these examples? It's not language features that make unreadable, unmaintainable code. It's not syntax that does it. It's bad programmers that cause this. And bad programmers, as you can see in that above item, can make any language feature unreadable and unusable. Like the for
loops up there. (You can see them, right?)
Now to be fair, some language constructs are easier to abuse than others. If you're a C programmer, however, I'd peer far more closely at about 50% of the uses of #define
long before I'd go on a crusade against goto
!
So, for those who've bothered to read this far, there are several key points to note.
goto
statements was written for a programming environment where goto
was a lot
more potentially damaging than it is in most modern languages that aren't an assembler.goto
because of this is about as rational as saying "I tried
to have fun once but didn't like it so now I'm against it".goto
statements in code that cannot be adequately
replaced by other constructs.godo
" abomination where an always-false do
loop is broken out of using break
in place of a goto
. These are often worse than judicious use of goto
.