Archive for the ‘as3signals’ tag
Events and Signals – Performance Tests
The new as3signals library devised by Robert Penner offers a replacement to the native AS3 event model. One benefit is that signals are more lightweight, and therefore faster. Grant Skinner’s Performance Harness is a widely accepted library for comparing the speeds of code execution.
I found the following results on Mac OS X, Flash Player 10.0.42.34, with a release build.
When an event (signal) is dispatched but nothing is listening for it:

When an event (signal) is dispatched and handled by one method listener:

The source code for my test methods follows:
If you browse these tests, you will notice that more tests were run than I have displayed above. The graphs above reference results from running the dataEventOptimised and dataSignal methods in each context.
These tests are not scientific. No attempt has been to control for player version, computer version, computer specifications, so on and so forth. You are invited to download and run these tests for yourself. If you do, remember that testing on a release build not a debug build is appropriate, and then please post your results as a comment, particularly if your results differ from my own.
Updates
For a comparison with good old fashioned callbacks, please put on your sarcasm snorkel and visit va.lent.in’s follow up post.
From the as3signals Google Group there was a suggestion that the Flash Player 10.1 might produce different results. Here are my results; they appear to corroborate the earlier results:
–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– performancetests.EventsTest (5 iterations) Player version: MAC 10,1,51,66 (regular) –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– method...................................................ttl ms...avg ms dataEvent 2344 468.80 dataEventOptimised 2270 454.00 dataSignal 313 62.60 simpleEvent 2755 551.00 simpleEventOptimised 2285 457.00 simpleSignal 174 34.80 –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– performancetests.CapturedEventsTest (5 iterations) Player version: MAC 10,1,51,66 (regular) –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– method...................................................ttl ms...avg ms dataEvent 2708 541.60 dataEventOptimised 2703 540.60 dataSignal 1182 236.40 simpleEvent 2724 544.80 simpleEventOptimised 2717 543.40 simpleSignal 1042 208.40 ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
RobotLegsPong Part 1 – Overview
Introduction
RobotLegsPong attempts to combine RobotLegs application framework with the as3signals event model and a Frame-Ticker (as well as a pinch of ASUnit unit-testing) to create a ‘game’.
It is an open-source project, available on GitHub as an example of using RobotLegs together with these other technologies.
Source Code: github/alecmce/RobotLegsPong
RobotLegsPong is not a very good game; it is playable only in the loosest sense. Bats require to be dragged in order to move (and there is no computer-logic to play against), so you could not really play against an opponent. The purpose of the exercise was to see what structure a game like Pong would take within the RobotLegs framework.
The purpose of this article is to describe the particulars of the technologies and why I chose them. In a follow-up article, I will look in more detail how RobotLegsPong is wired up.
Why I Chose These Technologies
RobotLegs
The RobotLegs framework is a lightweight, flexible application framework that allows coders to spend less time wiring up their application, and more time working on its functionality.
Frameworks are often criticised because they force developers to write code in a particular way, which might be inappropriate for a particular context. I have used Cairngorm, Pure MVC, as well as some proprietary frameworks, and have found that all of them do some things well, and do other things clumsily. So far I have not found this problem with RobotLegs, because most of the time it gets out of the way and lets you code; in fact, it does more than that: it reduces the amount of code you have to write.
as3signals
RobotLegs comes with an application event bus, but I have decided to circumvent that and use as3signals instead. as3signals allows you to define an object which acts as an event dispatcher within an application.
I like as3signals because describing an event as a Signal object allows my event model to be described through interfaces. as3signals is supposed to be fast too. Then again, interfaces are slow. The relative speeds of the approaches is interesting, but not a significant factor in my decision making process.
Frame-Ticker
The frame-ticker is a simple idea: rather than creating multiple enter-frame event listeners, each creating event objects, create one enter-frame listener and a main game loop iterating through those methods that need to be called per-iteration.
This implementation came out of a discussion on Twitter that I was involved in on the fringes; I wrote about it in a previous blog post.
ASUnit
Unit testing enables developers to test portions of their code in isolation, so that they can be confident that every method works exactly as the developer intended. They also represent a secondary form of documentation-in-code; if you want to know how I meant a method to work, reading the unit test will tell you almost everything you need to know (including, if a good test is missing, what I didn’t consider).
That said, I have not unit tested every method; in this example I have only unit-tested the geometric logic for the bats. This is bad practice, however under time constraints I think that it is most important to unit test what is complex, mathematical or ambiguous, since this is where behaviour is most likely to fall down.
[Inject]
The ‘trick’ to using RobotLegs is that you do not need to inject dependent objects into classes when you contruct them; this is done automatically. This code:
public class Dependee {}
public class MyExample
{
public var dependee:Dependee;
public function MyExample(dependee:Dependee)
{
this.dependee = dependee;
}
}
becomes this code:
public class Dependee {}
public class MyExample
{
[Inject]
public var dependee:Dependee;
}
The metadata tag [Inject] has the effect of automatically injecting the dependee into the class when it is constructed. This isn’t much on the face of it, but it is enough. It feels to me as though a quarter of my code is actually just wiring up classes so that they each have access to the classes that they need to function, or passing objects around methods. The [Inject] tag lets me shift all of that wiring into the RobotLegs framework.
Context
There is a little more to the RobotLegs story however; how should RobotLegs react when it comes across an [Inject] tag? It could construct a new Dependee object, or it could be that I want only one Dependee object to be injected wherever the [Inject] tag is found. This is where the Context class becomes meaningful.
In the PongContext, different classes are wired up in different ways. Their definitions are defined by adding injector mappings and the mediatorMap mappings in the startup method.
public class PongContext extends Context
{
override public function startup():void
{
...
injector.mapSingleton(DragMechanism);
injector.mapSingletonOf(Geometry, GeometryModel);
injector.mapClass(BatGeometry, BatGeometryModel);
...
}
}
injector.mapSingleton
injector.mapSingleton(DragMechanism)
mapSingleton indicates that only one instance of the class entered should be constructed. In this case, just one DragMechanism will be created, and injected whenever this is found:
[Inject] public var mechanism:DragMechanism;
injector.mapSingletonOf
injector.mapSingletonOf(Geometry, GeometryModel);
mapSingletonOf extends the mapSingleton idea to interfaces and their implementing classes. In this case the Geometry interface is mapped to the GeometryModel class. The injection is called as follows:
[Inject] public var model:Geometry;
No reference to the GeometryModel is needed in any class other than the PongContext. This allows a very pure use of interfaces across the application.
injector.mapClass
injector.mapClass(BatGeometry, BatGeometryModel)
injector.mapClass works a little differently; whenever a BatGeometry interface is flagged to be injected, a new instance of BatGeometryModel is constructed and injected into the class, so the following code is used to create the injection:
Each BatMediator needs its own BatGeometry object. By using the mapClass method, multiple BatGeometryModel objects will be constructed, one for each time the following code is found:
[Inject] public var model:BatGeometry;
Mediators and Components
public class PongContext extends Context
{
override public function startup():void
{
...
mediatorMap.mapView(Background, BackgroundMediator);
addChild(new Background());
}
}
mediatorMap references a slightly different aspect of the application: your view objects. The mediatorMap allows users to define associations between display objects and Mediators. These two parts comprise the View aspect of the standard MVC pattern.
The DisplayObject – in this case Background – is the asset that you want to be visible on the stage. In my pong example this is essentially just a Sprite, though it might just as well have been imported as a graphical asset in a SWC.
The Mediator is associated with the DisplayObject so that when an instance of the DisplayObject is created, the corresponding Mediator is also constructed. The BackgroundMediator looks something like this:
public class BackgroundMediator extends Mediator
{
[Inject]
public var view:Background;
override public function onRegister():void
{
...
}
}
The DisplayObject Background is injected into the BackgroundMediator when it is constructed. The DisplayObject can then be manipulated. It is an elegant solution that separates display object from UI logic.
addChild(new Background());
is all that is needed to wire the entire DisplayObject/Mediator combination.
RobotLegs & Tickers
The RobotLegs structure is particularly useful for wiring up a Ticker-based application because one ticker can be mapped as a singleton, and injected to all those methods that need to iterate every frame:
public class PongContext extends Context
{
override public function startup():void
{
...
injector.mapSingletonOf(Ticker, EnterFrameTicker);
...
}
}
RobotLegs with as3signals
I really like the style of event dispatching that as3signals provides, but my implementation demands that if one class requires another class then it must flag it to be injected, and then the signal wired up in a method flagged as [PostConstruct] (see GeometryModel). This doesn’t feel like the right solution.
Integrating as3signals with RobotLegs is beyond the scope of this article. It looks like Joel Hooks and Robert Penner are making inroads into this problem through as3signals’ Google Group. I look forward to seeing what they come up with.
Replacing ENTER_FRAME
Today an interesting discussion took place on Twitter, in which I was involved. It caught my attention for a variety of reasons, and I wanted to document the conversation, the problem and the solution here. It started when it was identified that Flash’s event dispatcher is sub-optimal in performance terms, and revolved around trying to find a solution.
Why replace the ENTER_FRAME?
Every event that is dispatched creates an object. An ENTER_FRAME creates as many objects per second as there are frames. If you have mutliple objects dispatching ENTER_FRAME events, that’s many objects creating event objects many times per second. Computationally, chains of “many” are one of those things you want to avoid. So, can we do better?
Doing Better
Robert Penner proposed creating an as3signal and using a MovieClip with two frames to dispatch that signal on each frame. He posted his idea to this GitHub gist.
One drawback to this approach is that it requires a MovieClip symbol with two empty frames, to which the two event dispatcher methods could be attached. I remembered reading in this excellent article by Bit 101 how using a [Frame] metadata tag would force your application to have two frames. This seemed to be what Penner needed for his functionality to work correctly, so I came up with my own GitHub gist which extends the concept. The code is also added ‘below the fold‘, at the bottom of this article.
[Update, after Jackson's comment, below] The idea behind the approach is that a frame-loop is an internal Flash player structure. It sits underneath the AS3 functionality, and so it doesn’t produce ENTER_FRAME events. By hooking into them we can produce our own iterative ‘event’ (Penner proposes using an as3signal), which doesn’t construct an object each time it is dispatched. It is a lovely idea, and quite distinct from invoking one ENTER_FRAME dispatcher on the root or stage of the application.
[Update, after Joa Ebert tweeted test results] Whether this method is superior to the ‘one-event ticker’ is open to question. Joa Ebert applied the frameloop concept to AudioBox and found no memory nor performance improvements.
Background
It all started today with a statement on Twitter from Robert Penner:
Listening to a single #AS3 enterFrame will create over 1000 event instances per minute. @robpenner
In fact, at a decent frame rate, you’re looking at 1800 event instances per minute. Across the blogosphere and on Twitter, there has been a lot of talk about the cost of object construction in AS3. People are pushing the limitations of the player, and are looking for performance optimisation wherever they can find it. Strategies such as object pooling are becoming mainstream in order to avoid the creation and destruction of objects. In the meanwhile, the internal Flash event model is creating and destroying huge numbers of objects to furnish us with an event model.
At the same time however, there has been a murmur of discomfiture about the state of the event model. (Not that I have much of a voice, but I chimed in to this debate as well!). The most notable result of this murmur was Penner’s decision to create as3signals. It is an on-going project to which I have contributed in a small way, and which I whole-heartedly support.
After Penner’s tweet, the #as3 twitterati (please tweet if there are glaring omissions from this list) became very excited indeed.
My initial thoughts led to the idea that maybe the setInterval/setTimeout functions, which are hangovers from AS2 might offer a solution – perhaps they shortcut the event system? Not only ain’t it so, they’re even worse as this Action Script Viewer deconstruction of the setInterval methods demonstrate.
So what else? Mike Chambers (aka @Mesh) in conversation with @TheFlashBum pointed towards a solution using a ‘ticker’; a single ENTER_FRAME dispatcher, and @bengarney confirmed that he also uses this technique.
It seems that @scottjanousek and @robpenner had the idea of using the player frameloop (which the solution offered here exploits) at pretty much the same time. (@scottjanousek’s tweets are protected, but it was reported by this tweet.)
Whether and how this vein of thought will develop is really interesting. It is fascinating how a tweet from one of the best-known ActionScript developers can provoke such a lot of attention from the general community. It is interesting too to see the envelope of what is possible being pushed.
Reflecting on as3signals
Robert Penner has recently produced a new AS3 library called as3signals (which can be found on both Git Hub and Google Code. I have used it in one small ongoing project, and I am really impressed with it.
as3signals includes two methods for adding listeners: an add listener which permanently adds a listener until a remove listener is called, and an addOnce listener which is a one-time listener only. This is a really welcome addition to the event model. Current projects are littered with code like this:
objectThatDispatchesEvent.addEventListener(EventType, onEvent, [false, 0, true]);
private function onEvent(event:Event):void
{
objectThatDispatchesEvent.removeEventListener(EventType, onEvent);
...actual code for handling event...
}
Penner’s signals performs the task much more neatly:
signal.addOnce(onEvent);
private function onEvent(data:Data):void
{
...actual code for handling event...
}
An interesting problem arises by having two methods for adding listeners that have different behaviours. What happens when you call first one, then the other, without calling a remove method in between? There are three main ways in which you could imagine the framework responding to this situation.
- Overwrite Model Each time a call redefines the relationship between signal and listener. In this model, subsequent calls overwrite the relationship;
- First-Wins Model The first call defines the relationship between signal and listener. In this model, subsequent calls are ignored. To change the relationship the current relationship should be first removed;
- Throw Error Model If you attempt to change the relationship between signal and listener without first calling
removethen an error is thrown.
Overwrite Model
The add method defines a stronger relationship between signal and listener than the addOnce method. If I had previously called signal.addOnce(listener) and then called signal.add(listener), I am intentionally strengthening the signal-listener relationship, and want the relationship to change. Conversely, I would expect the relationship to weaken.
A weakness of this model is that if you were to inadvertently change the relationship between the signal and listener, this would be extremely difficult to debug.
First-Wins Model
If you assign an event listener with addEventListener in the as3 native event model then you assign a priority to the listener which defines the order in which listeners are called (an optional parameter, which is 0 by default). In the as3 native event model, you cannot change the listener priority with further addEventListener calls unless you first call removeEventListener. Subsequent listener priorities are ignored. Similarly then, we could take this approach for add and addOnce. All subsequent calls are ineffective unless remove is called.
A weakness of this model is that if you intentionally change the relationship between the signal and listener, then your change should be effective! The following code certainly looks like it should work, but in fact the second line does nothing at all!
signal.addOnce(listener); signal.add(listener);
Throw Error Model
There are scenarios in which developers might purposefully use both add and addOnce methods without calling a remove method in between. However, there will likely be cases where the two methods are called interchangeably by mistake. This may not be easy to debug, and we could easily help the developer out here by changing the functionality so that if signal.addOnce(listener) and signal.add(listener) are called in either order without an intervening signal.remove(listener), that an error is thrown.
In many ways, this is an extension of the ‘first-wins model’, because it preserves the functionality of that model. However, it recognises that the developer that intends to change behaviour might write something like:
signal.addOnce(listener); signal.add(listener);
and handles it by throwing an error. The developer can then quickly change his code to either simply
signal.addOnce(listener);
or
signal.addOnce(listener); signal.remove(listener); signal.add(listener);
Summary
Penner argues that since the as3 native event model follows the ‘first-wins model’ with respect to priorities, this is the preferred model for handling addOnce and add calls. This argument is a little unsatisfactory, not least because if native as3 design decisions were in-themselves satisfactory, he wouldn’t have written as3signals in the first place!
My immediate preference was for the ‘overwrite model’, but I can see why people might adopt the ‘first-wins model’. I imagine that there is a relatively even split between the two camps. Therefore, I believe that throwing an error is the least confusing of all possible decisions. If an error is thrown, it is more difficult to write code that has unintended consequences. It forces the inclusion of remove methods, which makes code more readable. It is easy to explain and to document.
Hopefully it is obvious that I have enormous respect Robert Penner and the as3signals project. However, these small design decisions can have a large influence on workflow and they are important to get right. Penner has given the code an osflash package and he is clearly committed to writing this for the community. I first argued this point very briefly on one of his blog posts on as3signals, but it is an issue that deserved more serious attention. This sort of design decision would be well served by community discussion. If you have an opinion, please comment!
General Notes on Events
AS3 signals came out of a discussion on the problems that exist in the current event model. It is difficult to see Adobe deprecate this model any time soon, because their component framework, Cairngorm and the greater Flash/Flex community are now so dependent upon this model that it is unfeasible to imagine that they would abandon it.
The only way that the signals approach could be adopted en masse is probably if Adobe migrate to it in some future language ASx {x > 3}, or if some major libraries start to adopt it as their event model of choice.
In an earlier post of mine AS4 Thought Experiment, I attempted to think through my preferred API for a future language’s event model. The article was a response to community chatter about the event model, in part driven by Penner.
We share similar perspectives on how an event model ought to work. On reflection, I prefer Penner’s implementation with event.add(listener) and event.addOnce(listener) to my proposed event += listener, though I still stand by the argument that ideally, events should be demarcated from elements of an object through their own syntax; in my example by using #event... and by defining them in interface or class through public event drag or public event #drag. This, of course, is never going to happen!.
