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.

With each Box exception represented by its own class, the errors that can be generated by the setWidth( ) method are well-known to programmers working with Box instances. The exception types are visible outside the Box class, exposed appropriately to programmers working on the application. Just by glancing at the application class hierarchy, the programmer can determine the exceptions that relate to the Box class. Furthermore, if the programmer mistakenly uses the wrong name for an exception, the compiler generates a datatype error.

Now let's see how to add branching logic to our code based on the types of exceptions that can be generated by Box.setWidth( ). Pay close attention to the datatype of each catch block parameter:

var b:Box = new Box( );
var someWidth:Number = -10;

try {
b.setWidth(someWidth);
} catch (e:BoxOverflowException) {
// Handle overflow.
trace("An error occurred: " + e.message);
trace("Please specify a smaller value.");
} catch (e:BoxUnderZeroException) {
// Handle under zero.
trace("An error occurred: " + e.message);
trace("Please specify a larger value.");
} catch (e:BoxDimensionException) {
// Handle general dimension errors.
trace("An error occurred: " + e.message);
trace("Please specify a valid dimension.");
}

In the preceding code, if the setWidth( ) method generates a BoxOverflowException, the first catch block executes. If setWidth( ) generates a BoxUnderZeroException, the second catch block executes. And if setWidth( ) generates a BoxDimensionException, the third catch block executes. Notice that the error datatypes in the catch blocks progress from specific to general. When an exception is thrown, the catch block executed is the first one that matches the datatype of the exception.

Hence, if we changed the datatype of the first catch block parameter to BoxDimensionException, the first catch block would execute for all three kinds of exceptions! (Remember, BoxDimensionException is the superclass of both BoxUnderZeroException and BoxOverflowException, so they are considered matches for the BoxDimensionException datatype.) In fact, we could prevent all of the catch blocks from executing simply by adding a new first catch block with a parameter datatype of Error:

try {
b.setWidth(someWidth);
} catch (e:Error) {
// Handle all errors. No other catch blocks will ever execute.
trace("An error occurred:" + e.message);
trace("The first catch block handled the error.");
} catch (e:BoxOverflowException) {
// Handle overflow.
trace("An error occurred: " + e.message);
trace("Please specify a smaller value.");
} catch (e:BoxUnderZeroException) {
// Handle under zero.
trace("An error occurred: " + e.message);
trace("Please specify a larger value.");
} catch (e:BoxDimensionException) {
// Handle general dimension errors.
trace("An error occurred: " + e.message);
trace("Please specify a valid dimension.");
}

Obviously, the addition of the first catch clause in the preceding code is self-defeating, but it does illustrate the hierarchical nature of exception handling. By placing a very generic catch block at the beginning of the catch list, we can handle all errors in a single location. Conversely, by placing a very generic catch block at the end of the catch list, we can provide a general safety net that handles any errors not caught by earlier catch blocks. For example, in the following code, the final catch block executes only if the try block generates an exception that doesn't belong to the BoxOverflowException, BoxUnderZeroException, or BoxDimensionException datatypes:

try {
b.setWidth(someWidth);
} catch (e:BoxOverflowException) {
// Handle overflow.
trace("An error occurred: " + e.message);
trace("Please specify a smaller value.");
} catch (e:BoxUnderZeroException) {
// Handle under zero.
trace("An error occurred: " + e.message);
trace("Please specify a larger value.");
} catch (e:BoxDimensionException) {
// Handle general dimension errors.
trace("An error occurred: " + e.message);
trace("Please specify a valid dimension.");
} catch (e:Error) {
// Handle any errors that don't qualify as BoxDimensionException errors.
}

Remember, error granularity is a choice. In option 4 we created a custom Error subclass for each variety of exception generated by the Box class. This approach gives our program the greatest ability to respond independently to different types of errors. But such flexibility is not necessarily required in many situations. Let the needs of your program's logic dictate how granular you make your errors.

Warning

In the first release of the Flash MX 2004 authoring tool, a bug prevents catch statements from executing when the catch parameter datatype refers to a class that has been imported via the import statement. For example, in the following code, the catch statement never executes because SomeCustomError is imported:

import somePackage.SomeCustomError;
try {
throw new SomeCustomError( );
} catch(e:SomeCustomError) {
// This code should execute but it does not
// if the movie is compiled with version 7.0
// of the Flash MX 2004 authoring tool.
trace("Caught: " + e);
}

To work around the problem, we can include the full package name when specifying a custom error class as a catch block parameter. For example:

import somePackage.SomeCustomError;
try {
throw new SomeCustomError( );
} catch(e:somePackage.SomeCustomError) {
// Now that the package name is included, this code runs.
trace("Caught: " + e);
}

This bug is fixed in the Flash MX 2004 updater, available at: http://macromedia.com/support/flash/downloads.html.