Get rid of the old stuff

So. You are reading this page, perhaps you are one those guys waging wars against one of the oldest and most useful commands present in virtually all programming languages. Or you consider it to be an ancient heritage from the old times when computers were operated with a soldering bolt and DDT was used against the bugs. Or you are just interested in some insights about this "bad" command, because you are at a point now asking yourself WTF it is why everyone is so upset when stumbling about strange code others have written in dark hours and probably dark mental states, hacking a sleak solution for an itching problem they had with that cool algorithm.

You found a GOTO, and don't know what to think about it.

So you show the code to your collegues, most of which start shaking their heads and mumbling some incomprehendible stuff about object orientation, reusability andpasta. They have to know what they are talking about, because they know and frequently use some cool sounding words like "type design", "object orientated philosophy", "project maintainance", "quality assurance" and every other possible chain of words you can get when you take your dictionary, open it on page 244 and start writing down random words for later use just to appear cool and intelligent. They have to know, don't they.
Or you just started programming and read in your favorite textbook that the use of GOTO is deprechiated and should be avoided at all costs.

Well, this for starters: GOTOs really ARE bad. And they really ARE cool. If you don't believe the latter, go away and stay the way you are, the world needs people like you. If you do, read ahead.

First, let me tell you what I think the reason for all the GOTO-fuss is. This is a bit lengthy and it is my own opinion. If you know better, please let me know.

GOTO is one of the very basic commands understood by any CPU. In fact, EVERY program you compile will contain a ton of GOTOs, you just can't see them. And they probably are called "JMP" or "JP". If you take your newest and fanciest object orientated code to assembly language (and that is what the compiler does), every single IF statement and every loop needs those jump-commands to work at all.

Before we had those "high level programming languages" like C, FORTRAN, PASCAL and everything more advanced than assembly, programmers were forced to write their programs in assembly language. Doing so, one simply cannot avoid to use JMP once in a while. This is because of the very limited possibilities you have in assembly; every simple operation is a pain in the ass to implement and results in quite a few lines for just one variable assignment. One can imagine that this isn't exactly something to be understood the first time you look at it. This in fact was (sometimes still is) a real problem, programs written in assembly are extremely hard to comprehend for humans (but computers love it).
This again was the reason to invent the first "high level" programming languages. They couldn't do many of the things modern languages can do today, but they eased the pain of programming and reading others programs. Big time. But, being the first step of evolution in programming languages, they still had many similarities to assembly. GOTOs for example.
Now the complexibility of a program was not only determined by the complex operations needed to do some simple things, but the algorithms and the program itself. Programmers could start writing more complicated programs, and some of them clearly overdid it. The brains still trained to assembly language and the process of memorizing a ton of lines of the program while writing it made them write assembly code again. But this time, they used their high-level language to do so.

Let me give you an example. Consider this little prog, EXAMPLE_A:

modernancient
$test = true;
while($test) {
	switch($var) {
		case 1:
			$var = 3;
			break;
		case 2:
		case 7:
			$var = 9;
			break;
		default:
			$var += 5;
			$test = false;
			break;
	}
	$var -= 1;
}
$test = 1;
loop:
if($test == 0)
	goto loopend;
if($var == 1) {
	$var = 3;
	goto preloop;
}
if($var == 2)
	goto var_7;
if($var == 7) {
var_7:
	$var = 9;
	goto preloop;
}
$var = $var + 5;
$test = 0;
preloop:
$var = $var - 1;
goto loop;
loopend:

This is called "spaghetti code". And it isn't the worst i've seen. It isn't even the worst i've written. And if anyone today tried to sell me such code, I'd jump right into his face (sometimes I get the feeling that a company from redmond tries to do that anyway). And this, clearly, is not an example of good GOTO use. But there was a reason for writing such monsters, take a look again at the modern example. You'll notice some fancy statements like "while" and "switch" - those probably were not present in some ancient programming languages. The writing of spaghetti code was not avoidable and thus common use, but can be easily avoided today.

And now I'll give you another example of "modern" and "ancient" styles of programming - EXAMPLE_B:

modernancient
#define SOME_MEGS	1024*1024*24
#define ERROR 		-127
#define YIPPIE			0

char *arr1, *arr2, *arr3;

/* allocation */
if((arr1 = malloc(SOME_MEGS)) == NULL) {
	return ERROR;
} else {
	if((arr2 = malloc(SOME_MEGS)) == NULL) {
		free(arr1);
		return ERROR;
	} else {
		if((arr3 = malloc(SOME_MEGS)) == NULL) {
			free(arr1);
			free(arr2);
			return ERROR;
		}
	}
}

/* do some fancy stuff here */

free(arr3);
free(arr2);
free(arr1);
return YIPPIE;
#define SOME_MEGS	1024*1024*24
#define ERROR 		-127
#define YIPPIE			0

char *arr1, *arr2, *arr3;
int errcode = YIPPIE;

/* allocation */
arr1 = arr2 = arr3 = NULL;
if((arr1 = malloc(SOME_MEGS)) == NULL) GOTO error;
if((arr2 = malloc(SOME_MEGS)) == NULL) GOTO error;
if((arr3 = malloc(SOME_MEGS)) == NULL) GOTO error;

/* do some fancy stuff here */
GOTO done;

error:
errcode = ERROR;

done:
if(arr1) free(arr1);
if(arr2) free(arr2);
if(arr3) free(arr3);
return errcode;

And now you tell me which of these examples is easier to understand and maintain. If you have troubles getting the point, imagine the same example with arr1, arr2, arr3, arr4, arr5, arr6, arr7, arr8, three file handles, some mutexes and a nice little semaphore. If you still don't get it, go back to work and come back in a few weeks.

One of the first arguments against your GOTOs will be:

We'll handle those each at a time. If you heared others, please let me know.

unreadable code:

They may be right. But ONLY if you write GOTO-code as shown in EXAMPLE_A. If you do, listen to your collegues.

Consider this rule of thumb: The shorter the code, the easier to understand (of course there are exceptions). And now look at EXAMPLE_B, the allocation part. The code without GOTOs uses almost four times more lines of code than the code with the GOTOs (it would be more if that code wasn't formatted in my lines-saving mode, I don't like the braces in its own line each). Here, the use of GOTO is justified, because it makes the program EASIER to read. Use GOTOs only if it makes your code shorter.

leads to spaghetti

Well, there is that risk, yes. But you wouldn't have read that far if you were not a responsible programmer, looking for ways to improve yourself and your code. You have just to resist that small temptation to use GOTOs everywhere you think it might be of use but in fact is not.

Let me compare the whole case to this: you have a driving license, and you want to drive. Now you have the choice between two cars, a porche and a honda. Of course you take the porche because it has more power and can go faster, which again makes it easier for you to collect tickets for speeding. But you don't get tickets if you drive your porche and behave. Choosing the faster car doesn't make you a felon, it just gives you the freedom to do as you wish.

no reusability and object orientation

The object orientation argument is my favorite. Why on earth is it forbidden to use GOTOs in object oriented code? Object orientation is a way to organize your program as a whole, at a completely other level than the implementation itself.
Or, put into other words, when writing object oriented code, your functions become methods. That's it. There is no compiler-internal switch that disables object orientated functionality when the compiler happens to see a GOTO. If you believe that GOTO and object orientation cannot go hand in hand, start thinking. Perhaps you mistake "object orientation" for "high level" and "GOTO" for "low level" programming. And everyone knows that low level programming languages don't know jackshit about objects, right?
Again: don't mix one single method implementation and object orientated programming. The GOTO doesn't care, and you shouldn't either.

Reusability

There are people out there who believe that object code is reusable in all cases. Those tend to be the same who think that GOTOs cannot work in object orientated code. Those people have to understand one thing: object orientation does not create reusable code, programmers do. And GOTO doesn't have to do anything with it.

cannot debug

Please. Justified use of GOTO statements is in no way hindering debugging, see unreadable code. If you don't agree, go back where you came from and continue selling doughnuts and hotdogs.

 

 

Comments, corrections, additions, suggestions and flames go to:
Martin Domig <[email protected]>