flash try-catch

Flash Try Catch not catching custom Error Subclasses.

Last week I’ve been working on a custom error class for flash (as 2). This error class will become the key error handling mechanism in our framework. The base error class in our framework will be a RuntimeException.

What makes this class special is:

  • uncaught top level errors can be dispatched to a catch all handler
  • it contains the error cause, and the parent error
  • it contains a subcode

Not all that special however the first item makes this an (at least to us) indispensable asset in our framework.

Normally people have different ways of handling errors in Flash:

  • they ignore the fact errors occur and remain blissfully ignorant
  • they return some kind of errorcode or provide a method for error detection
  • they use the try-catch exception mechanism

In my opinion the easiest way to handle errors is to:

  • handle them at the level they occur
  • throw an Exception and let the caller handle it

Ignoring the fact errors can occur, or adding lots of methods to the signature of an object to allow (but not force) a client to detect errors are not really options I’d like to consider.

However throwing exceptions involves some intricacies, the two most important being:

  • it requires knowledge of lower level library errors and thus couples high level code to your libraries if you are not aware of this issue. In practice this usually means converting errors from one level to the next, or catching errors in general and not specific errors. So instead of throwing your webservice exception all the way to the frontcontroller, you catch the exception, convert it into a more general DataSourceFailureException and throw that.
  • it requires knowledge THAT code throws exceptions at all. RuntimeExceptions are not checked (checked exception do not exist in Flash), therefore the compiler does not enforce them.
  • displaying uncaught exceptions

The base error class in Flash is the Error class.
If you use:

throw new Error("test");

your swf will show “test” in the trace output BUT only if you run in the IDE.

What our RuntimeException class does is the following:

  • it extends Error, so you can use it through throw new RuntimeException();
  • it sets an interval to run after the current callstack unwinds, pushing itself onto a list of not yet handled errors
  • it allows itself to be consumed, removing itself from the list of not yet handled errors

After the current callstack unwinds, the interval kicks in. Two things might have happened.
One, the error may have been caught and consumed :


catch (e:....) {
//show and handle error here, never just catch it, that negates the use of error handling
....
e.consume(); //consume the error so it doesnt propagate any further
}

Two, the error may not have been consumed.

If the error has been consumed, it would have removed itself from the list of unhandled errors.
The moment the interval kicks in, all errors that are still unhandled at that moment are passed to an error handler.
If the RuntimeException class cannot find an error handler, it creates a default error handler, which does nothing more than create a textfield at the stage and print error information to it.

In effect what this does is that you can throw exception throughout your code, which you should catch and handle.
However, if you forget to catch one, it will show up at runtime on your stage instead of remain hidden.

One step further and you can imagine it is very easy to implement an Assert class with an AssertionFailedException.

The assert class can be used in your code, for example:

public function setParent (pParent:MovieClip) {
Assert.assert (pParent != null, "Parent movieclip cannot be null.");
.....
}

If you fail to pass a reference, the assertion will fail and a message will show up on your screen. Combining this with our reflection package, the message on our screen looks something like:


ASSERTION_FAILED in MyClass.setParent, called from MyClassB.myMethod, with parameters ......

Ofcourse this check could be even more extensive including runtime type checking, but we should wonder how far we should take this. In most cases, compiling using MTASC with the strict flag, most type checking will already have been done. Ofcourse calling the method like:


setParent (myClips["clip")

circumvents typechecking, and might cause some subtle errors which do not trigger exceptions.

In some cases, adding a type check is easy:

Assert.assert (MovieClip(pParent) != null, "Parent movieclip cannot be null.");

However if you do this using an array:

Assert.assert (Array(pArray) != null, "Given array cannot be null.");

it will work as expected in MTASC but not in the Flash IDE, since MTASC will cast it, but the Flash IDE will create a new array for you. In other words, this would require you to implement some more extensive checks.

Which brings me to another framework class:
ReferenceValidator

The Reference validator is an alternative to the Assert class, specifically created for testing references for null and their types.

A common scenerio is where you wrap a clip with your own screen class. The screen class needs a reference to the clip and the components on it, which is where the ReferenceValidator comes in. It copies all the references for you from the clip to the wrapper, testing the values for their types and null (if required).

Ok, that’s it for now, I hope to post more on the framework coming into being at the moment.

Before I forget:
One major bug I encountered is that in order to catch a custom error you have to specify the full path to the error.
So in other words:


catch (e:MyCustomError) {

}

will not work, whereas :


catch (e:my.full.package.to.my.error.path.MyCustomError) {

}

will work.

Very annoying. Ah well such is life.

Leave a Reply