Sunday, October 26, 2008

When not to use events

I've been doing a moderate amount of ActionScript/Flash CS3 coding lately and I've been learning a few things.

Many languages have facilities that seem on the surface to be cool ways to save time but that can hurt you badly if you don't understand where they should and shouldnt be used.  In Java, a common beginner's stumbling block of this sort is the reflecion API.  In AS3, it's event dispatchers.

Event dispatchers seem like a great general way to tie code together.  All you need do is declare an object's class as an EventDispatcher and anyone else can register with it to be notified of events.  This can be very handy HOWEVER it is key to realize that a an event dispatch is NOT the moral equivalent of a function call on the listener.  Making this mistake can cause no end of subtle errors.

What then is a difference?  Well, when an object's method makes a direct call to a method on another object, that call is synchronous.  The called method is executed immediately on the same call stack as the calling object.  As Flash CS3 is a single-threaded execution engine, this means that order of direct method calls is deterministic and predictable.

However, when  you dispatch an event, all that happens is that the event you dispatched is added to the event dispatcher's event queue.  That method invocation will not actually happen until the queue gets processed.  This will happen at some later time that is not under your control.  Event dispatches are asynchronous, which is to say their order is not entirely deterministic.

Different events dispatched to the same event queue will reliably get processed in the order they were dipatched in.  However, every instance of an event dispatching class has its own queue.  What order these queues are processed in in relation to each other is again, up to the execution engine and something you have no control over.

The upshot of all this is this, event dispatch in AS3 is fundementally asynchronous.  You should never use it for making calls to other code where there are requirements on the order in which such calls get executed.  Use a direct reference to a listening object instead.

If you follow this rule, then the single-threaded nature of AS3 will keep you from ever having to worry about race conditions leading to heisenbugs.  (A heisenbug is a bug that changes when you try to examine it and they are among the hardest to find and fix.)  Ignore this rule and I guarantee you will have exactly that.

No comments: