Copyright © 2004 O'Reilly Media, Inc. All Rights Reserved.
Essential ActionScript 2.0
By Colin Moock
June 2004
ISBN: 0-596-00652-7
More info... .
Available from booksellers or direct from O'Reilly Media, www.oreilly.com.

Cover image
This content is excerpted from the above-named O'Reilly publication, with permission, by agreement with ActionScript.org.

Earlier we learned that exceptions in a try block can be thrown either directly or as the result of a method call. In reality, an exception can be thrown anywhere in an ActionScript program, even on a frame in a timeline! Given that an exception can be thrown anywhere, how does the ActionScript interpreter find the corresponding catch block to handle it? And what if no catch block exists? These mysteries are resolved through the magic of exception bubbling. Let's follow along a bubbly ride with the ActionScript interpreter as it encounters a throw statement in a program. During the following dramatization, the interpreter's musing are shown in code comments.

When a throw statement executes, the interpreter immediately stops normal program flow and looks for an enclosing try block. For example, here's a throw statement:

// INTERPRETER: Hmm. A throw statement.
// Is there an enclosing try block for it?
throw new Error("Something went wrong");

If the throw statement is enclosed in a try block, the interpreter next tries to find a catch block whose parameter's datatype matches the datatype of the value thrown (in the present case, Error):

// INTERPRETER: Great, I found a try block. Is there a matching catch block?
try {
throw new Error("Something went wrong");
}

If a matching catch block is found, the interpreter transfers program control to that block:

try {
throw new Error("Something went wrong");
// INTERPRETER: Found a catch block whose parameter datatype is Error!
// The hunt's over. I'll execute this catch block now...
} catch (e:Error) {
// Handle problems...
}

But if a matching catch block cannot be found or if the throw statement did not appear within a try block in the first place, then the interpreter checks whether the throw statement occurred within a method or function. If the throw statement occurred in a method or function, the interpreter searches for a try block around the code that invoked the method or function. The following code demonstrates how the interpreter reacts when, within a method, it encounters a throw statement that has no enclosing try block:

public function doSomething ( ):Void {
// INTERPRETER: Hmm. No try block here. I'll check who called this method.
throw new Error("Something went wrong");
}

If the code that invoked the method or function is enclosed in a try block, the interpreter looks for a matching catch block there and, if it finds a match, executes it. The following code demonstrates an exception thrown out of a method and caught where the method is invoked (i.e., one level up the call stack).

class ErrorDemo {
public function doSomething ( ):Void {
// INTERPRETER: Hmm. No try block here.
// I'll check who called this method.
trace("About to throw an exception from doSomething( ) method.");
throw new Error("Something went wrong");
}

public static function startApp ( ):Void {
// INTERPRETER: Aha, here's who called doSomething( ). And here's
// an enclosing try block with a catch block whose
// parameter datatype is Error! My work's done. catch
// block, please execute now...
try {
var demo:ErrorDemo = new ErrorDemo( );
demo.doSomething( );
} catch (e:Error) {
// Handle problems...
trace("Exception caught in startApp( ), thrown by doSomething( ).");
}
}
}

Tip

The call stack is the list of functions and methods currently being executed by the interpreter at any given point in a program. The list includes the functions and methods in the reverse order from which they were called, from top to bottom. When a function is immediately below another function in the call stack, then the lower function was invoked by the higher. The lowest function in the call stack is the function currently executing.

You can use the Flash debugger to view the call stack for the current movie, as described in the Flash authoring tool online Help, under ActionScript Reference Guide → Debugging. Note, however, that the Flash debugger displays the currently executing function visually on top rather than on the bottom. That is, the visual display of the call stack in the Flash debugger is the reverse of the call stack discussed in the preceding note. Ultimately, the distinction is arbitrary—the glass is half full or it's half empty; the stack works top down or bottom up, depending on your point of view.

In the preceding code, an exception thrown by a method was caught by a try/catch block enclosing the method call statement. However, if no try block is found around the function or method caller, the interpreter searches up the entire call stack for a try block with a matching catch block. The following code shows a method throwing an error that is caught two levels up the call stack:

class ErrorDemo {
public function doSomething ( ):Void {
// INTERPRETER: Hmm. No try block here.
// I'll check who called this method.
trace("About to throw an exception from doSomething( ) method.");
throw new Error("Something went wrong");
}

public static function startApp ( ):Void {
// INTERPRETER: Aha, here's who called doSomething( ). But still
// no try block here. I'll check who called this method.
var demo:ErrorDemo = new ErrorDemo( );
demo.doSomething( );
}
}

// Meanwhile, elsewhere in the program...
// INTERPRETER: Aha! Found a try block that has a catch block whose
// parameter's datatype is Error! My work's done. catch block,
// please execute now...
try {
ErrorDemo.startApp( );
} catch (e:Error) {
// Handle problems...
trace("Exception caught where Error.startApp( ) was invoked.");
}

Notice that the interpreter finds the try/catch block despite the fact that it surrounds not the error-throwing method, nor the caller of the error-throwing method, but the caller of the method that called the error-throwing method!