ActionScript signals, events and interfaces

! Warning: this post hasn't been updated in over three years and so may contain out of date information.

Signals is a great new ActionScript Framework which offers an alternative to Flex Events. Whilst it has a nice set of features that give it advantages over Flex events, there is one claimed benefit that I find difficult to accept. This selling point, popular with signals fans, is that an interface can specify a signal contract for classes implementing that interface.

Consider the following interface by Diego Ponce de León (@diegoxleon):

Any class implementing IVisible must implement shown(), hidden(), drawn() and cleaned() and thus provide the four signals. Diego (and many others, including signals’ author Robert Penner) claim that this functionality is a great signals feature and that it cannot be achieved with Flex events. I have two reactions to this claim:

  1. Is it really that great a feature?
  2. The “can’t be done with events” claim is not actually correct

The rest of this post will attempt to justify both reactions. I’ll deal with them in reverse order.

The “can’t be done with events” claim is not actually correct

Whilst the IVisible example above is very neat, it doesn’t do anything that cannot be achieved with events. A signal nicely encapsulates three elements of an event: the dispatcher, the event type and its metadata (ie the data type associated with the event and thus the extra data that the listener can receive). With this in mind, we can rewrite IVisible to specify an event contract instead:

Clearly this is nowhere near as tidy as Diego’s signal-based interface, but that isn’t the point. The point is that it is possible to create an event-based contract through an interface. Further, with the aid of a helper class, we can even make it just as tidy as the signals example. The helper class is a value object that encapsulates an event’s signature, ie the dispatcher, event type and metadata associated with an event:

Having defined this class, we can then rewrite our interface as:

Is it really that great a feature?

To my mind, neither the signal-based, nor the event-based solution, are really of much use as neither is a true interface contract. In both cases, there are two problems.

The first problem is that both specify vague compile-time contracts over the signal/ event listener. Until runtime, there is no way to know how many parameters, and of what type, the signal listener needs to be. Likewise until runtime, there is no way to know which event datatype the event listener needs to support.

The second problem is that events and signals are asynchronous and thus non-deterministic. Because of this, a class could implement any of the versions of IVisible above and yet never dispatch an event or signal.

To overcome these problems, ActionScript would need to implement built-in events with say C#-style delegates that specify the listener’s method signature. Further the compiler would have to check that any implementing class contains reachable code that will dispatch all events defined by the interface. I really can’t see this happening any time soon.

Conclusion

Signals is a great framework, of that there is no doubt in my mind. It has many really nice features, such as fire-once events, support for easily removing all listeners from a dispatcher and better type safety than events. One supposed advantage though is bogus in my view and that is claims related to using it with interfaces.

10 thoughts on “ActionScript signals, events and interfaces

  1. Hi David, thanks for this explaining what you had in mind, and sparking what is sure to be an interesting discussion.

    There’s a small typo: _dispatcher – dispatcher;

  2. The EventSignature is an interesting idea. The constructor is similar to NativeSignal:

    http://github.com/robertpenner/as3-signals/blob/master/src/org/osflash/signals/natives/NativeSignal.as

    The code to consume EventSignature would look like this, if I understand correctly:

    widget.shown.dispatcher.addEventListener(widget.shown.eventType, onShown);
    widget.shown.dispatcher.removeEventListener(widget.shown.eventType, onShown);

    // inside Widget
    shown.dispatchEvent(new shown.metadata(shown.eventType));

    It’s a little long-winded, compared to:

    widget.shown.add(onShown);
    widget.shown.remove(onShown);

    // inside Widget, no Event necessary
    shown.dispatch();

  3. I concede your point, that it’s possible to put AS3 Events in interfaces. However, this approach doesn’t look like something anyone would actually use.

    > with the aid of a helper class, we can even make it just as tidy as the signals example

    Yes, your IVisible with EventSignature is as tidy as the IVisible with Signal. But actually using that interface is not as tidy, if my usage example above is correct.

  4. > The second problem is that events and signals are asynchronous

    I would say this is incorrect, unless you have a different definition of “asynchronous”.

    A method executing synchronously remains in the same call stack and blocks progress of the program until it is finished. Asynchronous execution is non-blocking. Obligatory Wikipedia link:

    http://en.wikipedia.org/wiki/Asynchronous_I/O

    Signal and EventDispatcher are blocking and synchronous. If Signal used Timer on dispatch(), it would be asynchronous.

  5. > Until runtime, there is no way to know how many parameters, and of what type, the signal listener needs to be. Likewise until runtime, there is no way to know which event datatype the event listener needs to support.

    I assume you’re saying there’s no way for the *compiler* to know the signal parameters. I agree, and it really bugs me. This is a language limitation of AS3, as far as I can see.

  6. > Is it really that great a feature? … neither is a true interface contract

    I agree that putting events/signals in AS3 interfaces isn’t as good as we would imagine in a more expressive language. But that doesn’t take away from the value added by the interface as it stands.

    For me and others, it’s a significant improvement over using string-based channels. The contract is strengthened by making the events/signals tangible properties of the object. I would argue that the delta of improvement by doing this is greater than the remaining amount that isn’t yet possible. Events/signals as properties eliminate the possibility of many wiring mistakes that would not even generate a run-time error. But I need to do a blog post on that. =)

    Thanks again for initiating this discussion; I think it’s fruitful.

  7. Thanks for this post David, I’ve have learnt something from it. All encouragement that I can offer you to right that blog post Robert is contained in this sentence. 🙂

  8. @Robert,

    Apologies for my slowness in replying to you.

    Firstly, your code example looks about right to me. Looks like we both can conceed to each other, as I conceed that whilst it is possible to put Flex events in interfaces, it is unlikely anyone would.

    Perhaps I have the Flex event model wrong, but I was under the impression that many events are dispatched UIComponent.callLater() and thus fire off the frame timer. This would make them asynchronous.

    As for the rest, I have no argument over the superiority of signals versus Flex events.

Comments are closed.