AS3 has a controversial new keyword: goto. It’s not documented, but this article will tell you how it works. It’ll also talk about why you might want to use it to improve performance or even make your code more readable (gasp!).

First, goto isn’t documented in Adobe’s documentation so what I’m writing here I’ve learned only by experimentation with the AIR 13 SDK. Here’s a very basic usage:

goto a;
foo();
 
a:
goo();

This code skips over the foo() call and resumes at the a “label” where the goo() call is made.

You can also skip backward:

var visited:Boolean = false;
someblock:
	row("someblock");
	if (visited) goto after;
	visited = true;
	row("now have visited");
 
goto someblock;
 
after:
	row("after");

This prints:

someblock
now have visited
someblock
after

These are contrived examples to show how goto works. How about an example you’d see commonly in other languages like C?

var sum:int = 0;
for (var y:int = 0; y < rows; ++y)
{
	for (var x:int = 0; x < cols; ++x)
	{
		sum += grid[y][x];
		if (sum > threshold)
		{
			goto after;
		}
	}
}
after:
print("out of the loop");

Basically, it’s a way to break out of nested loops without needing to check a flag on each loop iteration. However, AS3 offers a cleaner way just for this purpose:

var sum:int = 0;
outer: for (var y:int = 0; y < rows; ++y)
{
	for (var x:int = 0; x < cols; ++x)
	{
		sum += grid[y][x];
		if (sum > threshold)
		{
			break outer;
		}
	}
}
print("out of the loop");

This version simply labels the outer loop and then adds that label as a parameter to the break statement. But what if you wanted to skip beyond the point right after the end of the loop? Now that we have goto, this is easy:

var sum:int = 0;
for (var y:int = 0; y < rows; ++y)
{
	for (var x:int = 0; x < cols; ++x)
	{
		sum += grid[y][x];
		if (sum > threshold)
		{
			goto tooMuch;
		}
	}
}
after:
return sum;
 
tooMuch:
return -1;

This version can skip the “success” case where the sum is returned and instead return an error code. But it would be very easy and arguably much cleaner to just replace the goto statement with the return statement.

Where goto shines is when you want to “fall through” these cases, similar to when you don’t put a break statement in a switch case label.

var tex:Texture;
var prog:Program;
var vb:VertexBuffer3D;
var ib:IndexBuffer3D;
try
{
	tex = context3D.createTexture(...);
}
catch (err:Error)
{
	goto errorTex;
}
 
try
{
	vb = context3D.createVertexBuffer(...);
}
catch (err:Error)
{
	goto errorVB;
}
 
try
{
	ib = context3D.createIndexBuffer(...);
}
catch (err:Error)
{
	goto errorIB;
}
 
try
{
	prog = context3D.createProgram(...);
}
catch (err:Error)
{
	goto errorProg;
}
 
return true;
 
errorProg:
	// Clean up index buffer then fall through to clean up vertex buffer and texture
	ib.dispose();
errorIB:
	// Clean up vertex buffer then fall through to clean up texture
	vb.dispose();
errorVB:
	// Only texture to clean up
	tex.dispose();
errorTex:
	// Nothing to clean up
	return false;

If we didn’t have goto, we’d need to duplicate some of these cleanup blocks like so.

var tex:Texture;
var prog:Program;
var vb:VertexBuffer3D;
var ib:IndexBuffer3D;
try
{
	tex = context3D.createTexture(...);
}
catch (err:Error)
{
	return false;
}
 
try
{
	vb = context3D.createVertexBuffer(...);
}
catch (err:Error)
{
	tex.dispose();
	return false;
}
 
try
{
	ib = context3D.createIndexBuffer(...);
}
catch (err:Error)
{
	tex.dispose();
	vb.dispose();
	return false;
}
 
try
{
	prog = context3D.createProgram(...);
}
catch (err:Error)
{
	tex.dispose();
	vb.dispose();
	ib.dispose();
	return false;
}
 
return true;

This approach doesn’t scale very well as you add more and more cases that could fail. It spreads the error handling throughout the function, so it’s arguably less clean than the goto version. But its worst trait is that the error handling code is duplicated over and over violating the Don’t Repeat Yourself (DRY) philosophy. Sure, you could avoid this with functions:

var tex:Texture;
var prog:Program;
var vb:VertexBuffer3D;
var ib:IndexBuffer3D;
 
function getErrorCode(): Boolean { return false; }
function cleanupTex(): Boolean { return getErrorCode(); }
function cleanupVB(): Boolean { tex.dispose(); return cleanupTex(); }
function cleanupIB(): Boolean { vb.dispose(); return cleanupVB(); }
function cleanupProg(): Boolean { ib.dispose(); return cleanupIB(); }
 
try
{
	tex = context3D.createTexture(...);
}
catch (err:Error)
{
	return cleanupTex();
}
 
try
{
	vb = context3D.createVertexBuffer(...);
}
catch (err:Error)
{
	return cleanupVB();
}
 
try
{
	ib = context3D.createIndexBuffer(...);
}
catch (err:Error)
{
	return cleanupIB();
}
 
try
{
	prog = context3D.createProgram(...);
}
catch (err:Error)
{
	return cleanupProg();
}
 
return true;

But now we’ve created four local functions complete with performance-destroying activation objects. To fix this we could split the local functions out into private member or class functions of the class, but we’d then have to do even more work and type even more code to pass the local variables as parameters to them. The error handling code would be further spread out through the file and, perhaps worse, exposed unnecessarily to other areas of the code that have no interest in the internal error handling of the function. Plus, performance is still being unnecessarily reduced by making several slow function calls.

In short, goto is the fastest and cleanest way to solve this problem. In circumstances like these, it’s a nice addition to the language.

Spot a bug? Have a question or suggestion? Post a comment!