Making sense of Flash compile-time and run-time errors
Every new version of ActionScript has had its impact on the compiler and error handling. Since ActionScript 1, that had loose typing and was suited well for small-scale scripting projects, things have changed considerably.
With ActionScript 2 Flash community first saw the compile-time type checking and class-based syntax which basically allowed Object-oriented programming approaches. Despite the class-based inheritance that took AS2 closer to Java for instance, compiling still took it to AS1 bytecode over legacy matters. So basically the class-based inheritance that allowed the OOP approach was a layer on top of the existing prototype-centric AS1.
With Flex 2 and ActionScript 3 the scripting language changed a lot. The whole thing was restructured and new AS3-specific virtual machine (AVM2) was introduced. For those working in Flash IDE prior this era, it changed a lot. With a "habit" of procedural programming they had to rethink it. On the new platform, even if compile-time errors made sense referring to the line error occurred at, run-time errors didn't really help them out much, e.g.:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
or slightly better
ReferenceError: Error #1069: Property property0 not found on Doc and there is no default value.
but also without a line number. Something that can be understood at run-time, we're dealing with bytecode.
Nevertheless the situation is a bit similar to Java and you can actually quickly scope the above error using the call stack backtrace:
ReferenceError: Error #1069: Property property0 not found on Doc and there is no default value.
at Doc/handleTimerResult()
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at flash.utils::Timer/tick()
so it runs up to handleTimerResult and then gets stuck. A quick dive into the (illustrative) code reveals that the trace is trying to access property0 during the while iteration at line 51.
package {
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class Doc extends MovieClip {
public var property1:uint;
public var property2:uint;
private var timer:Timer;
public function Doc() {
init();
}
private function init():void {
trace("Doc Class initilized!");
setProperties();
initTimer();
}
private function setProperties():void {
setProperty1();
setProperty2();
}
public function setProperty2():void {
property2 = randomOf100();
trace("2nd property set to "+property2);
}
public function setProperty1():void {
property1 = randomOf100();
trace("1st property set to "+property1);
}
private function randomOf100():uint {
return Math.random() * 100;
}
private function initTimer():void {
timer = new Timer(1000, 5);
timer.addEventListener(TimerEvent.TIMER, handleTimer);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, handleTimerResult);
timer.start();
}
private function handleTimerResult(event:TimerEvent):void {
var i:int = 3;
while (i--) {
trace("Property "+i+": "+this['property'+i]); // run-time error
}
}
private function handleTimer(event:TimerEvent):void {
setProperty1();
setProperty2();
trace("Properties reset!");
}
}
}
In most cases, if a class is structured reasonably, the above logic should deliver nicely. If this is not the case, in Flash IDE, instead of the regular Cmd/Ctrl + Enter "Test Movie" functionality, you also have "Debug Movie". It will launch standalone Flash Player and provide you with the line number in the backtrace:
ReferenceError: Error #1069: Property property0 not found on Doc and there is no default value.
at Doc/handleTimerResult()[/Users/[...]/Doc.as:51]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at flash.utils::Timer/tick()
Related references: