My Critique of AS3 Events - Part 2 - The Dispatchening

September 6, 2009


Come with me as I chase more windmills.

flash.events.EventDispatcher could be easier to clean up


removeAllEventListeners(), where are you? Everyone's been looking for you.
And wouldn't it be great if I could mark some listeners to be removed automatically the first time called?

Whatever, this is OOP, it shouldn't be too hard to subclass and do it myself.
Let's create a new class, override addEventListener() and...

flash.events.EventDispatcher is difficult to extend


Oh snap, looks like my subclass can't access all those listeners in EventDispatcher.
Guess I'll maintain my own array of listeners so I can remove them all easily. It's been done before:

http://k2xl.com/wordpress/2008/07/02/as3-eventmanager-class-removealllisteners/
http://code.google.com/p/k2xl/source/browse/trunk/as3classes/src/util/k2xl/EventManager.as

But now my array has strong references to all the listeners. The useWeakReference option won't help me now.
Ohhh, I know!
Dictionary
can haz weak references?
Theoretically, yes.
Unfortunately, though, storing methods in a weak keys Dictionary is buggy.

Besides, Dictionary has no concept of order.
What if I need to know what sequence the listeners are in?
Would I create a weak reference Dictionary for each listener and have an array of dictionaries?
It's been done, but I'm not going to consider that until the Dictionary bug is fixed.
Hmm... Can haz special array with weak references? Keep dreaming.

The point being, flash.events.EventDispatcher is a black box--the frustrating kind. Adobe Flash Player engineers, if you're reading this and you know a magic namespace to open up the listeners, please let me know. While we're dreaming, how about a look at the source code for EventDispatcher?

Oh well, at least we have the IEventDispatcher interface. It seems like a lot of work, but I should be able to write my own dispatcher from scratch and satisfy the interface, right?

IEventDispatcher cannot be implemented


Not entirely true. It can, but not with pure AS3. But I don't know that yet.

So I work away building my own implementation of IEventDispatcher. I'm adding listeners, I'm removing listeners, I'm even removing all listeners! Things are looking up.

I'm at the exciting part now: the dispatchEvent() method. Ok, find the listeners array for the event type, good, good. Now I'll just set the event.target property to this and iterate through the--

GACK!

Event.target is read-only


NOOOoooooo!!! 

I can picture the meeting in the secret DOM Level 3 Dungeon:

Level 3 Paladin:  "Would anyone ever need to change the event target?"
Level 3 Seer"Inconceivable!"

But, there must be some way of changing the event target, right?

IEventDispatcher cannot be implemented without using EventDispatcher


You see, flash.events.Event has a secret alliance with flash.events.EventDispatcher.
Only EventDispatcher is entrusted with the awesome power to change target.
We're so much safer that way.
And yes, you will have to extend flash.events.Event because there is no event interface.

Here's an offer you can't refuse: implement an interface using one special implementation of that interface!

You can write your own dispatcher if you like, but if you have a hang-up about target and currentTarget being null all the time, you'll have to instantiate EventDispatcher and have it dispatch the event for you. Which means it will need all your listeners and your Gmail password. Which makes you wonder why you even bothered.

I hope this gives a sense of the obstacles that arise when trying to extend the AS3 event system. It fights you at every turn. Please let me know if I've overlooked or misunderstood anything.

At least this article was fun to write. It solidifies my rationale for building and using my own event system when I don't need to integrate with the display list.

Labels: ,


12 Comments:

Anonymous Ben Clinkinbeard said...

Would an array of listener UIDs work?

7:15 PM  
Blogger Robert Penner said...

Ben, do you mean in order to have weak references in an array? Can you expand on your idea?

7:31 PM  
Blogger professor torpedo said...

I am sitting here looking at the exact same problem. i'll sum up my observations in a few minutes....

9:08 PM  
Anonymous Ben Clinkinbeard said...

Yea, that is what I meant but now I realize that only solves half the problem. It would allow you to store an ordered list of listeners without creating references but you'd have no way of looking them back up since there is no getByUID() method. I think you're right, we're screwed. :)

9:12 PM  
Blogger professor torpedo said...

I have had tons of success, using the Swiss Flash User's Group ( SFUG ) [ LOVE YOU CATS ! ] events for AS2,
to emulate AS3.

You have the complete source, these are real classes, so when you extend them, you know *exactly* what you're doing. If you want to make some sort of variation and write to the interface, you know exactly what you're changing from the original implementation.

I'm going to try and port ch.sfug.events.EventDispatcher to AS3....
we had already modified the sfug class for mixin with an initialize(p_target)... lifted straight outta AS1.

Being able to see all the moving parts really is important....
I once thought EventDispatcher was a black box, coming up from AS1, but in AS2 you really can scour out all the classes. In FDT, with MTASC classes, you can shift click all day around the real guts of your flash app.
MTASC was great for clarifying all of that.
AS3? swc. meh.
AS3 EventDispatcher, great for what it's great for. But if you reaaaaallyyy want to own the process...
in AS2, running the ch.sfug.EventDispatcher was a breeze.

I'll let you know how it turns out. or you can let us know what you think about bringing these up to AS3...

http://code.google.com/p/sfug-as-library/source/browse/#svn/trunk/as2/trunk/src/ch/sfug/events

I have also had a lot of luck porting people's various Iterators between AS2 and AS3. again,
if they weren't transparent, you would be seriously crippled....

the sfug classes let us run AS2 side by side with AS3 with super easy ports because of the event model.
Maybe the AS2 eventdispatcher class can save us from the can't touch this AS3 EventDispatcher. maybe.
can't weak references really just be locally scoped variables in the dispatcher ? I might be on crack. but...

thanks again for all your edgy thinking sir. excuse me if i have missed something obvious [again]

d

9:42 PM  
Blogger Robert Penner said...

Hello Professor Torpedo (how often do I get to say that?),

The SFUG EventDispatcher is almost identical to the AS2 EventDispatcher a work colleague and I developed.

http://code.google.com/p/sfug-as-library/source/browse/trunk/as2/trunk/src/ch/sfug/events/EventDispatcher.as

We had the same method signature for adding and removing listeners. The extra for scope allowed us to eliminate Delegate creations all over the place.

I have something fairly different in mind these days--an event system inspired by C#.

11:19 PM  
Anonymous Xavi Beumala said...

Hi Robert,

very nice post! If just blogged about a way you could use (with debugger player) to retrieve a list of listeners from an EventDispatcher:
http://www.rialvalue.com/blog/2009/09/08/does-an-eventdispatcher-have-subscribed-listeners/

12:25 AM  
Blogger Bart said...

What's also great (NOT) is that you cannot re-use custom events.. (eg: you cannot use an object pool).. so the amount of object creation in a more complex application is simply insane. We tried to, but the blackbox is doing some sneaky stuff that breaks your Event-objects.

3:34 AM  
Blogger EECOLOR said...

In what cases do you want to remove all event listeners?

In quite some years I never found myself in a situation where I needed to do that.

In almost every case it is enough to just remove the event dispatcher object. Can you give a practical example where you need to remove all?

7:06 AM  
Anonymous Jamie Lemon said...

In the case where you have got a lot of objects setting up things like maybe Event.ENTER_FRAME and you have that triggering ( in hyperspace sometimes... ) A complex RIA can get like this after a while, believe me .... ( so when you unload a view, remove a display object , start a refresh removeAllEventListeners() would be pretty damn useful ). I've come to Robert's conclusion - that, yes, a central bespoke event listener manager is the way to go...

2:13 AM  
Anonymous Anonymous said...

Maybe i'm dumb but the only think i really agree is the removeAllListeners(). All your critics (which are relevants) are made because you want use a different event model (which is not a bad idea at all).

Anyway, wouldn't it possible to use a dictionary with weak references, store the target as the key and an int as the value ? With some work you would have a kind of "reversed array" you could loop through and removeListeners...

My last question would be : how would you handle the flash event model with yours :

Would you have to use both in the same code, depending on what event you wanna use (because some events might be replaced) or maybe internally handle flash event model in your framework ?

3:49 AM  
Blogger Robert Penner said...

@Anonymous:

>>
Anyway, wouldn't it possible to use a dictionary with weak references, store the target as the key and an int as the value ? With some work you would have a kind of "reversed array" you could loop through and removeListeners...
<<

How can I store the target as the key, when addEventListener() doesn't have a parameter for the target? I don't follow your reversed array idea...

3:16 PM  

Post a Comment

<< Home

© 2008 Robert Penner| Based on a template by Gecko & Fly.

This page is powered by Blogger. Isn't yours?