Ideal Language

The Ideal Language has “goto”

“goto”: the demonized programming construct. This little expression allows you to jump to somewhere else in the code while skipping the expressions in between. Opponents say it leads to spaghetti code and has no business in modern programming. Most new languages buy into this argument and don’t include a goto expression, yet fail to include a solution for the places where goto is still useful.
There are several situations where goto produces the cleanest possible code. Trying to cram the same login into a series of if statements, or loops, in fact can lead to more obfuscated code. Within state machines, including parsers, it often has a role. For highly optimised code it provides a good solution for producing lean code. All in all there are enough valid reasons for goto that not including it in a language is a mistake.

Alternatives

Wherever there is an alternative to goto it should be used. For example, breaking out of multiple levels of nesting can be done with a “continue” keyword which accepts a label for a loop construct. Common exit code from a function can be handled via a “finally” block. Often a goto can be avoided simply by using a closure or local function with a return statement.

Restrictions

Nobody will claim that unlimited goto is ever required. We aren’t trying to recreate setjmp/longjmp, which are truly hard to resolve in a modern language. To preserve stack integrity goto can only ever allow one to go up in the stack. Preserving caller context may also require that goto can only be used within a function.  These limitations are reasonable, and most uses of goto live within these.

Implications

Obviously if the execution path is going to be jumping about very clear rules about variable life-time are necessary. This is the clearest reason why goto can only ever go up the stack. Going down the stack means entering scopes of variables which haven’t yet been initialized. So using a goto will unwind the stack up to the level of the destination. In terms of resources this essentially requires the RIAA pattern for resource management: we can’t allow the goto to leak resources.

In the destination scope it also follows that the construction of any variables is not skipped. (C++ has this rule.) That is, in the scope where the label exists, all variables after that label must have been constructed and initialized prior to the goto statement.

Questions

Jumping outside of the current function probably doesn’t make sense. The most significant reason is that there is no guarantee that the calling function has the destination label defined. We need to make some allowances however. If the language makes use of anonymous functions, closures and lambdas it may make sense to allow goto in those scopes. If those components are specified elsewhere however, for convenience, or reuse, would goto be allowed?

Examples

Here is a random collection of places where goto may be a suitable option.

Breaking from inner loops

This a common example of where goto is helpful. You have an inner loop and wish to break out of the outer loop. For example, say you wish to find an element in a matrix.

	location_t where;
	for( int i=0; i < num_rows; ++i )
	{
		for( int j=0; j < num_cols; ++j )
		{
			if( matrix(i,j).is_what_we_want() )
			{
				where.set(i,j);
				goto found;
			}
		}
	}
	throw error( "not-found" );

	found:
	//do something with it

There are obviously other ways to doing this to avoid the “goto”, but this code is perfectly clear and easy to follow. It does not make sense to code this another way if the only reason is to avoid using “goto”.

Redoing a block of code

You have a bit of code which you might need to execute multiple times within the same scope. A “goto” can sometimes be the clearest option to express this logic.

	redo:
		...
		if( must_redo_expr )
			goto redo;
		...
		if( another_redo_expr )
			goto redo;

The alternate, and popular approach, is to use a while loop.

	while( true )
	{
		...
		if( must_redo_expr )
			continue;
		...
		if( another_redo_expr )
			continue;

		break;
	};

The loop approach slightly obscures the logic of the code. It also has a severe limitation that if you have an inner loop you simply can’t use “continue” to get to the outer loop. Furthermore, it introduces a new scope which can be a problem for certain variables. Now, you can virtually always use a loop instead, but why would you do that if it requires a lot of code juggling and ends up making the code less readable?

Error handling

Error handling within a function can more complicated than simply returning “false” or throwing a simple exception. Said error handling may depend on numerous local variables.

	int function( int a, int b, int c )
	{
		int d = 0;
		...
		if( detect_problem )
			goto broken;
		...
		if( other_problem )
			goto broken;
		...
		return d;

	broken:
		report( a, d );
		resolve( c );
		return -1;
	}

Repeating the error handling code multiple times would be bad (code duplication is always bad). You might be able to create an external function, but then you must take care to pass all the variables correctly in each case.

This type of error handling is kind of like a miniature exception handling. You can basically create local “try-catch” conditions without the overhead (both runtime and syntactic) of using exceptions. It keeps your primary logic easier to read by pushing error handling off somewhere else.

State machine

Sometimes the logic of an algorithm is just not amenable to representation as a tree. This quite often appears when doing parsing or encoding.

	void handle_stream()
	{
	idle_state:
		...
		if( detect_high )
			goto high_state;
		if( detect_low )
			goto low_state;
		if( detect_end )
			goto end_state;
		goto idle_state;

	high_state:
		...
		if( continue_high )
			goto high_state;
		goto low_state;

	low_state:
		...
		goto idle_state;

	end_state:
		...
		return;
	}

Though state machines are pretty common we don’t see this type of code very much. Most of such code tends to be created by code generators, such as a parser generator or a protocol generator. In cases where performance is not an issue you’ll instead see a higher level functional, or object based approach — using a “switch” statement or function pointers you can avoid using “goto”, though the logic is the same.

23 replies »

  1. I find your post really important. People I work with have fanatical opinions about ‘goto’; they do not even try to think if it should be used or not in a particular case, but will just repeat like mantra “goto is evil”. This is very uncommon to see someone consider the usage of ‘goto’. I also believe it is occasionally useful for representing complex an untypical control structures. In fact, the way I approach the problems of complex loops is to first use goto’s and only then to check if it can be replaced with something else.
    Anyway, if you need to use break’s and continue’s in your loop, they are comparably ugly to goto’s.
    On the other hand, the design of the language should be to allow writing common tasks easily and briefly and for uncommon tasks to leave longer and harder but manageable ways. Since complex control structures are rare, perhaps goto’s could be abandoned in favor of local functions. I think every problem solvable with gotos can be rewritten with local functions. Such rewrite is longer, and a bit less readable (not necessarily slower), but this should be an acceptable solution for rarely occurring situations. Of course, it still depends whether your “Ideal Language” is lo-level or high level. One other goal for the “Ideal Language” is to keep it small. And getting rid of a feature (like goto) would make it smaller.

    • There are unfortunately a lot of oft repeated programming mantras. ‘goto’ can be used poorly, but virtually all language constructs can be used poorly. I think it is very important in the design of a new language not to drop functionality. This is, in my opinion, the major reason why C and C++ are still used, not because they’re great languages, but because they have a great degree of flexibility and options.

      If a new language wants to get rid of ‘goto’ it has to, as you say, provide alternatives to this. ‘break’, ‘continue’, and ‘switch’ are all just specialized versions of this same construct. Some kind of cleaner, unifying construct would be nice. Local functions, or closures, would also help remove some of my uses of goto (which I’ll admit are very limited, but where I use them I have no reasonably alternative). The issue here is that a language has to be able to make some kind of performance guarantees. Quite often I have to avoid certain convenience constructs simply because their run-time cost (size or speed) is simply too high for what I want to achieve. I know that most often this isn’t so important, but in the places where it is I need a bit of control about what happens.

    • I’ve scanned my code and added some examples of using “goto”. It may however be a bit a hard to see in this small tidbits why “goto” is cleaner than other options.

  2. “Goto” is an evil ogre, but, its daughters (“continue”, “break”, “while”, “do-while”, …), are sexy…

    • Please feel free to provide examples and we can compare. Do keep in mind these are demonstrating form and not are not complete examples — so I might give additional information as to why an alternate form would not be applicable in some situations.

  3. Sure. I’ll just share my personal opinion on each of the above examples:

    1) BREAKING FROM INNER LOOPS. I think such examples would be much more clear with a return statement.

    2) REDOING A BLOCK OF CODE. I think while-continue is much more clear. It shows (rather than obscures) the intention of the code. Unlike a goto statement, a continue means one specific thing: redo.

    3) ERROR HANDLING. I think exceptions are a far more flexible, powerful, and clear mechanism for error handling.

    4) STATE MACHINE. I would not code a state machine in a single monolithic function. I think it’s much more clear to have small, manageable, and testable functions/classes rather than one big function.

    • In the case of “BREAKING FROM INNER LOOPS”, I think iterators often make such code more clear.

    • 1. See my post https://mortoray.com/2012/01/22/never-use-the-continue-keyword/ for a short discussion (in comments as well) about how it isn’t always easy to separate inner-loops into functions. There are scoping issues with the variables at times. If possible, then yes, separate functions are preferred.

      2. This we’ll just have to disagree on this then — I just consider goto cleaner here. Note, I don’t consider this construct a loop, that’s why I don’t like using a loop construct. But, just like 1, if you are otherwise prevented from making a separate function inside inner loops you have an issue.

      3. For me duplication removal is priority 1, and if each block of code has to issue the exact same exception then we should have common code. Due to scoping rules on the variables we can’t easily call a function here. The only ways to remove the duplication are either a MACRO or the GOTO. (Separately, repeating the same code can often significantly increase the code size, which may be an issue in some applications)

      4. While it may be clearer such state machines are often used in places where performance is critical and chaining little functions can be a significant performance hit.

      Note that I’m not arguing goto should be a common replacement for other constructs, just at certain times it would be the better option. In domains where high levels of optimization are not required an abstracter approach may often be clearer. I am talking about the ideal language here however, and optimization to the extreme should be supported in an ideal language, and goto is way to provide for this.

    • I guess we’ll just disagree on a lot of things, but I’ll agree with you on one point: If your language or compiler has a weakness, you may need to use workarounds. But if we’re talking about an ideal language, performance issues shouldn’t be a problem because I the ideal compiler should be much better than me at optimizing code. Even a pretty-good compiler should be able to beat most people most of the time, in my opinion, and without requiring people to uglify their code. There’s a place in the world for languages that let you optimize to the extreme, but due to the smells involved, I couldn’t call them ideal.

    • Agreed. Though until we can find a way to solve that, we’ll need the undesired constructs.

      The title should be “The Ideal language has goto but you should never need to use it”

  4. Pingback: Quora
  5. Can’t help thinking that the state machine example is a bad application of goto, indeed most of these can be rewritten;.

    For the state machine, if functions can be inlined, with equivalent optimisation to tail-call-optimisations, the approach of splitting into state functions is no less efficient, and a hell of a lot clearer.

    The main problem with goto is it does not state intent, Why are you branching to that particular place? The absence of intent is a nightmare for both readers and programmers.

    Further, providing constructs like this,almost certainly means they will get widely abused. I’m currently porting some code to .NET, and the original is littered with bad examples of goto abuse.

    Then again, I come from an extreme, Smalltalk-like position where I consider most control flow should be in the library, not in the language.

  6. Further, your error-handling example looks like VB’s (<= 6) On Error Goto construct. Its a nightmare, and mountains of VB6 code will happily illustrate the dangers of that approach.

    The only place I can consider goto necessary is for extremely low-level code, such as typically output by code generators. If such constructs are provided, I'd want some way of marking a code region as "unsafe" to warn casual users off using these abominations.

    • My idea of the ideal language would be to support all domains. Thus if there is a single location where goto is the preferred approach then it should be supported. Definitely my examples have other ways to be solved (but perhaps not in current languages).

      I’m also leaning towards that the ideal language may look different per module, and as you say, allow things like “unsafe” blocks. Though honestly I think “goto” can be implemented perfectly safely.

  7. The oft-maligned ‘goto’ is a low-level construct — it’s in assembly, for example — and in certain very specific (small!) circumstances, I think it’s as clear as any other construct. I’m not a fan of code that twists itself to accommodate a coding style — total clarity is the primary goal of any source code. Whatever is the most clear wins, and every once in a while a ‘goto’ is just the right tool.

    But it is low-level, and it doesn’t carry much of a semantic, so it usually does create hard-to-read code if used beyond very local circumstances. It’s so low-level because “branching” is a fundamental concept behind the definition of “algorithm.” As such it’s not really part of the vocabulary of high-level code.

    • I agree that it is low-level, and I general only use it when needing utmost performance, or when the language doesn’t offer full error handling structures. In particular, in C, I don’t have finally blocks, deferals, or destructors. Unfortunately some newer languages have also lacked sufficient constructs, but since they also lack goto the option to use it wasn’t there.

      I do now find that with full lambda support, local functions, templates, and similar features, the need for goto outside of optimization is not needed. I can usually express myself cleaner without it now. For example, in C++11 I use closures to handle a few of the listed cases above.

      I will endeavour in Leaf to not require goto by ensuring all cases where it makes sense have a similarly, or cleaner, alternative.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s