September 13, 2009

AS3 Signals Getting Stronger

A lot has happened in the last four days.

What Happen? We Git Signal

The majority of commenters preferred Github to Google Code so I moved the Signals project there:

I am experimenting with mirroring back to the Google Code SVN. It's going ok so far.

Committing Early and Often

I made about 20 commits to Github this weekend. Some highlights:
  • The package is now org.osflash.signals (previously com.robertpenner).
    I wanted it to have more of a community feel. Thanks Aral for the namespace!
  • Listener priority is now supported in ISignal.add().
  • ISignal.dispatch() can now send any number of arguments to listeners.
    Zero or ten, it's up to you.
  • Various classes and APIs were renamed for clarity.
  • More unit tests and fixes.

Going Native

Since my last post about connecting EventDispatchers to Signals, I had another idea for integration:

Why not use EventDispatcher for the actual dispatching but wrap it in a Signal facade?

Presenting the NativeSignal class, which lets you have your cake and eat it too.
  1. Take any EventDispatcher, e.g. Sprite.
  2. Create a NativeSignal that targets an event of the dispatcher:
    // in a subclass:
    click = new NativeSignal(this, 'click', MouseEvent);
    // or decorating an instance:
    click = new NativeSignal(theDispatcher, 'click', MouseEvent);
  3. Enjoy the Signal APIs and features.
  4. Dispatch from the NativeSignal or the EventDispatcher. Both use Flash's native dispatchEvent()
If you're hesitant to put your trust in new dispatching code, or you want to keep your EventDispatcher options open, this is the gateway drug for you. You don't have to give up anything. All the native functionality stays, and the ISignal interface can be piped in like frosting, wherever you like. Doesn't that sound delicious?

Get Connected

September 9, 2009

The Community Responds to AS3 Signals

The community response to my Signals event system has been very encouraging. In the two days since I opened it to the public, there have been dozens of comments on my announcement and re-tweets. People have been quite positive and interested. No one has told me I'm wasting my time (you could be the first!).

The best part has been people's insights for improving Signals. I'm been rapidly integrating them as you can see in my commits for the last two days. A special thanks goes out to Richard Lord for helping me understand AS3 event bubbling and how to implement it in Signal.

Connecting EventDispatchers to Signals

[EDIT: I renamed EventDispatcherSignal to NativeRelaySignal]

I received a very clever idea by Jacob Wright for relaying EventDispatcher events to Signal listeners. I implemented it in a new EventDispatcherSignal NativeRelaySignal class. It lets you easily wire, say, a Sprite to send native events through your own signals. The same goes for any object that implements IEventDispatcher.

Here's how you could create a Sprite subclass that uses a Signal for the click event:

public function MySprite()
 click = new NativeRelaySignal(this, 'click', MouseEvent);

// listen elsewhere
function onClick(e:MouseEvent):void { ... };
// fire a MouseEvent manually to test
mySpriteInstance.dispatchEvent(new MouseEvent()); // onClick is fired

The implementation of wiring the Signal to the IEventDispatcher is very simple:

[EDIT] I added listener count checking to avoid bugs (thanks to Richard Lord).

// in
override public function add(listener:Function, priority:int = 0):void
 var prevListenerCount:uint = listeners.length;
 // Try to add first because it may throw an exception.
 // Account for cases where the same listener is added twice.
 if (prevListenerCount == 0 && listeners.length == 1)
  IEventDispatcher(target).addEventListener(_name, dispatch, false, priority);

Also, Jacob's twin Tyler sent me some mind-bending ideas for radical memory efficiency. He takes lazy instantiation to a whole new level. I'm still reeling from thinking about things like Signal inheriting from Array and using a getter's arguments.callee as an index into a Dictionary. We'll see how this evolves.

Github vs Google Code

Question: Who would prefer using Github for the Signals project, rather than Google Code? I've used Git a bit and would be open to moving to it if contributors preferred that.

September 7, 2009

My New AS3 Event System: Signals

I have more critiquing of AS3 events I could do, but I figured I'd throw my hat in the ring.

I've been working on something I call Signals. It's a new approach for AS3 events, inspired by C# events and signals/slots in Qt.

Today I created my first-ever Google Code project:

EDIT: I moved the project to Github.

I listed features with short code samples there. I'm having a hard time pasting them into Blogger without re-doing it all. Here are the Concept and Philosophy sections for a start:

The Concept

  • A Signal is essentially a mini-dispatcher specific to one event, with its own array of listeners.
  • A Signal gives an event a concrete membership in a class.
  • Listeners subscribe to real objects, not to string-based channels.
  • Event string constants are no longer needed.


  • Composition and interfaces are favored over inheritance.
  • Events in interfaces are a good thing.
  • Event types are classes, not strings.
  • Event classes should focus on the data they contain, not on who sends them.
  • Event classes should not contain string constants that various other classes use.
  • Test-Driven Development (TDD) is essential and fun.
  • So far, not a single static keyword in the source.
  • No singletons.

The Project Home Page has the feature listing and code examples.

I want Signals to be really good, and I'm open to changing anything and everything to improve it. So please check it out and post your impressions, critiques and suggestions.

September 6, 2009

My Critique of AS3 Events - Part 2 - The Dispatchening

Come with me as I chase more windmills. 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... 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:

But now my array has strong references to all the listeners. The useWeakReference option won't help me now.
Ohhh, I know!
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, 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 property to this and iterate through the--

GACK! is read-only


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, has a secret alliance with
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 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.

AS3 Events - 7 things I've learned from the community

Since posting my initial critique of AS3 events, I've learned a fair bit through community feedback. Thanks everyone for your comments and corrections; I edited my original post accordingly. Conversations on Twitter brought out further subtleties of how developers work with AS3 events.

I still have more critique in me, but first I'll eat a little humble pie. I haven't actually worked much with custom events in the display list. Most of my AS3 development has been in code libraries that operate independently of the display list. Thus, my custom events generally don't need to bubble or cancel. So when I look at the AS3 event system, I see APIs that often add clutter without a benefit to my project. For developers building RIAs, AS3 event capturing, targeting, bubbling and canceling is wonderful. The standard is called DOM Level 3 Events for a reason. It's great if you're in a DOM, but that doesn't mean it's the most usable solution for events in general. But I'll have to leave that discussion for the next critique.

What I've learned about AS3 events in the last 3 weeks

  1. Custom events can bubble when you dispatch them from a DisplayObject.
    I'd never tried this, and thought that only Flash Player events (MouseEvent, etc.) could bubble.

  2. Custom events can be canceled.
    The Event APIs cancelable, preventDefault() and isDefaultPrevented() are not just for Flash Player events.

  3. Despite Grant Skinner's argument for using weak listeners, some experienced developers choose not to.
    Some say relying on weak references has caused more problems than anticipated. However, Grant advocated always removing listeners explicitly. Weak references are just "an added level of security".

  4. Flash Player 9 didn't always garbage collect weak references.
    This is fixed in Player 10.

  5. Storing method references in a weak keys Dictionaryis buggy.
    References may be duplicated or garbage collected prematurely. Technically, this isn't part of AS3 events. But when trying to extend the event system, you may use a Dictionary to store listeners or callbacks. Developers who've done this have learned not to use weak keys.

  6. When an event has no listeners, EventDispatcher.dispatchEvent() is unnecessarily slow.
    Grant Skinner's patch is a 5x speedup, apparently. 

  7. Some say listener priorities are smelly.
    Like MovieClip.depth in AS2, priority numbers introduce dependencies into your code. These become increasingly difficult to manage in larger systems, as new code must take into account the  priorities in existing code.

    An alternative is to rely on the order the listeners are added. The original dispatcher can add itself as a listener first and thus ensure it has first crack at the event. Unless a different listener misbehaves and steals the spotlight with a higher priority...

    This is an interesting one. I haven't had to deal with this issue and I'm not sure what I think yet. The listener order does start to feel similar to the stacking of movie clips in AS2. Who's going to come out on top? Do we need an equivalent of getNextHighestDepth() for listener priorities [shudder]? I'm reminded of how the Macromedia V2 components would grab the highest possible depth with its own depth manager, rendering getNextHighestDepth() useless. Is there a word for bad nostalgia? How about "nastalgia"?