Showing posts with label as3. Show all posts
Showing posts with label as3. Show all posts

Thursday, 14 February 2013

Tinkering With Ash

Last October I was fortunate enough to attend the excellent Try Harder conference for the second time. I have spoken before about how inspirational the event is where every attendant must give a talk on something they are passionate about. One of the talks was by David Wagner's and was on 'The Value of Tinkering' and it inspired me to tinker with TypeScript which led to my Recursive Chrome Extension.

Before I go any further I should mention that there is a Try Harder 'Level Up' session taking place in April that is open to new attendees, I thoroughly recommend you check it out!

Following on in the same 'Tinkering' vein I have decided to investigate an AS3 library by another Try Harder attendee Richard Lord:

logo

 

What is Ash? Well direct from the Ash Website:
Ash is a high-performance entity system framework for game development.

An entity system is a way to organise the code for a game that is efficient for both code execution and code management. It uses composition rather than inheritance for sharing features between game objects and uses a data-oriented approach to separate the game state from the game logic. This makes it much easier to manage the code and to manage the game state.

Im not going to go into the details too much of why composition over inheritance is a good idea as Richard has already done a much better job than I ever could in these two posts:

If you haven't got a clue what im talking about when I say Entity or Component I strongly recommend checking out his posts first.

The reason why Ash has piqued my interest is because for the last three years I have been working with Entity-Component systems for games but in a totally different way. The way I have been using and developing started with the Push Button Engine (PBE) method and later expanded out to include Dependency Injection culminating in the Swft Framework.

Ill give one example of why am starting to fall in love with Ash:

In PBE and Swft the components contain data and functions. They can also declare dependencies (via [Inject]) which are automatically fulfilled when a component is added to an Entity. The functions in the component are able to act on their own data, other components and interact with the game as a whole.

One problem with this method is that components are largely tied to their entity and once attached aren't really free be removed or added. The reason is because other component may have dependencies that depend on that component being part of the Entity. Removing the component will cause the game to crash. This becomes a problem when you want to enable a certain chunk of functionality for a certain time then disable it, what you tend to end up doing is adding the component at Entity creation time then inside of it toggling its behaviour with a boolean.

In Ash components are pure data with the bulk of the functionality being contained within systems. Sure you can have functions in a component but they only act on their own data. There are no hard dependencies between components. What this means is that components are much more free to be added and removed from Entities. So how do component function together then? Well that's where Systems come in.

Systems are classes that contain the logic that makes up your game. When added to the engine they grab one or many lists of Nodes. A Node simply defines a collection of components that must exist on an Entity. In effect it declares the dependencies that this System needs to operate. What's neat about this is that this list of nodes is constantly changing as components are added and removed from entities. The Ash Engine manages this all for you so all the system need do is iterate over the linked list of Nodes each frame and execute its logic.

Systems also must not declare dependencies between each other. This rule means you don't end up with large dependency hierarchies between Systems. This frees up systems to be added and removed from the Engine with no side effects! This is rather remarkable as it lets you do crazy things that you couldn't normally do when there are many dependencies between systems. For example your game could have a Blitting based rendering system, then halfway through a running the game you could swap that out that System and replace it with a Starling based rendering System!

Thus far I have only spent a limited amount of time tinkering with Ash but I am having a whole lot of fun. I have started work on a little game to experiment around with the framework. At the same time I have been exploring Starling, the hardware accelerated 2D rendering framework built on Stage3D. Thus far I have produced this little map editor:


Click to place a block, shift and click to remove, scroll mouse to change block type and hold control and click to zoom in / out.

Its only a tech demo at the moment and as such hasnt got any game play elements. Im not entirely sure what to turn it into but as a platform for tinkering with Ash its been great.

Its too early to share the code at the moment but if you would like to see how some Ash code looks I strongly recommend you check out Richard's Asteroids example on GitHub. I was really quite taken aback by how neat and modular the code is. The example is provided in 4 different flavours, one using RobotLegs one with Starling one with SwiftSuspenders and one with no dependencies at all. The fact that the code still works and looks simple in all the examples really demonstrates the versatility of the framework :)

Friday, 19 October 2012

Try Harder 2012 Slides



Because Monocle is now available to everyone via the FB 4.7 Beta2 I guess its okay for me to now post these slides.

Wednesday, 17 October 2012

Try Harder 2012



The above is what it looks like from a speakers position at the try { harder } conference. (click to embiggen).

I had indented to write this post a couple of weeks ago, immediately after the conference but STRATO denied that. But oh well, here it is anyways.

This year was the second annual try { harder } conference / coder retreat / brain explosion. I have spoken about try harder in the past but it really is a uniquely awesome event. Its a rather intimate affair  where 10-15 people getting together and sharing ideas and knowledge in the tranquil forests of Center Parks Nottingham.

The format was largely the same as last year. Everyone gave a talk on a topic of their choosing, some were technical talks such as David Arno's on C# (NCrunch, MVC & Mono) or Mattes Groeger's on developing iOS social games. Quite a few talks were on non-technical things such as David Wagner's talk on 'the value of tinkering' or Stray's talk on 'Heuristics, collaboration special sauce'. Each talk was fascinating and the wide range of topics covered adds to the special feel of this event.

When deciding what to give my talk on I couldn't make my mind up. I have been through a lot this year from launching my first business then having it fail to exploring a great many new tools and technologies to creating and launching my first mobile game. Not to mention all the cool things I have had the pleasure to work on at Playdemic. In the end it was a tweet from David Wagner who suggested that I talk about an exciting tool I had been experimenting around with lately; Adobe Monocle.

Adobe Monocle is the new profiler for flash and mobile content from Adobe and really is very nice. It currently still in pre-release and hence under NDA so I had to ask for permission before giving the talk on it. I haven't had permission to blog about it get so if you want to find out more about it then check out this video that Thibault Imbert made a few months back:



I personally think it is a game changer for flash game makers. It makes development so much easier by giving better insights as to what is going on inside your game.

Try Harder is more about simply giving talks however. Each afternoon was set aside for pair programming sessions. Like last year we were given a deceptively simply problem then split off in pairs to try to solve that problem in a test-driven way. The kicker was that at the end of your hour with your parter you then must delete all your work and start again with the next person.

The problem we were given this year was "to find and score the palindromes with a length greater than 3 chars in a given string". Seems simple, but when you get into it, it is deceptively complex. Because of the varied programming backgrounds of the attendees there were many different tools and technologies used.

Of the 6 different partners I had I solved the problem using: Javascript, Actionscript3, Haxe, C#, Java and Ruby using TextMate, Flash Builder, FlashDevelop, Visual Studio and IntelliJ. It was fascinating to see the multitude of ways to solving the same problem

Try Harder is held in the heart of the forests of Center Parks Nottingham. This adds to a sense of "getting away from it all" and I found it to be a really helped with concentrating on what we were doing. In many of the evenings I enjoyed walking around the forests or swimming in the pool or sampling David Wagner's rather excellent scotch whisky that he brought with his all the way from Scotland (cheers Dave!)

   

So if you cant tell I had a great time at try { harder } this year. I think because I knew what to expect this time I could relax and enjoy the whole thing a little more. I also approached the event with a much more open mind which meant I could relax more and enjoy the format.

Bring on try { harder } 2013!

Saturday, 30 June 2012

On Porting RobotLegs2 & SwiftSupenders2 to Haxe



I originally hoped that this post would be about my successful completion of a RobotLegs2 port to Haxe however something else has come up (more on that in a later post) so instead im just going to talk about the process and progress of the port thus far.

So although there is already an excellent RobotLegs 1 Haxe port out there by David Peek, I decided I would like to try to port the brand new Robot Legs 2 Framework  which offers a great many improvements over the original.

Rather than beginning the port from scratch I decided to use as3hx to take the legwork out of converting the AS3 code to Haxe code. To get the tool you must first checkout the library from its google code repo at: http://caffeine-hx.googlecode.com/svn/trunk/projects/as3hx/

Once downloaded its just a simple matter of compiling the source into a neko executable:

[codesyntax lang="powershell" lines="normal"]
haxe as3hx.hx

[/codesyntax]

Then you can run it with:

[codesyntax lang="powershell" lines="normal"]
neko as3hx.n

[/codesyntax]



To convert a AS3 project give it an input and output folder:

[codesyntax lang="powershell" lines="normal"]
neko as3hx.n -vector2array -uint2int robotlegs2 robotlegs2out

[/codesyntax]

In this case the input folder is the source download from the RobotLegs2 GitHub page.

It will start to convert but will get stuck:

[codesyntax lang="powershell" lines="normal"]
C:/Users/MikeC/Desktop/as3hx/robotlegs2/src/robotlegs/bender/extensions/eventCommandMap/api/IEventCommandMap.as
C:/Users/MikeC/Desktop/as3hx/robotlegs2out/robotlegs/bender/extensions/eventcommandmap/api/IEventCommandMap.hx
C:/Users/MikeC/Desktop/as3hx/robotlegs2/src/robotlegs/bender/extensions/eventCommandMap/impl/EventCommandExecutor.as
C:/Users/MikeC/Desktop/as3hx/robotlegs2out/robotlegs/bender/extensions/eventcommandmap/impl/EventCommandExecutor.hx
C:/Users/MikeC/Desktop/as3hx/robotlegs2/src/robotlegs/bender/extensions/eventCommandMap/impl/EventCommandFactory.as
C:/Users/MikeC/Desktop/as3hx/robotlegs2out/robotlegs/bender/extensions/eventcommandmap/impl/EventCommandFactory.hx
C:/Users/MikeC/Desktop/as3hx/robotlegs2/src/robotlegs/bender/extensions/eventCommandMap/impl/EventCommandMap.as
C:/Users/MikeC/Desktop/as3hx/robotlegs2out/robotlegs/bender/extensions/eventcommandmap/impl/EventCommandMap.hx
C:/Users/MikeC/Desktop/as3hx/robotlegs2/src/robotlegs/bender/extensions/eventCommandMap/impl/EventCommandTrigger.as
Called from ? line 1
Called from Run.hx line 66
Called from Run.hx line 55
Called from Run.hx line 55
Called from Run.hx line 55
Called from Run.hx line 55
Called from Run.hx line 55
Called from Run.hx line 55
Called from Run.hx line 38
Called from C:\Motion-Twin\Haxe/std/neko/Lib.hx line 63
Called from Run.hx line 29
Called from as3hx/Parser.hx line 117
Called from as3hx/Parser.hx line 131
Called from as3hx/Parser.hx line 488
Called from as3hx/Parser.hx line 415
Called from as3hx/Parser.hx line 589
Called from as3hx/Parser.hx line 794
Called from as3hx/Parser.hx line 744
Called from as3hx/Parser.hx line 919
Called from as3hx/Parser.hx line 964
Called from as3hx/Parser.hx line 1106
Called from as3hx/Parser.hx line 1016
Called from as3hx/Parser.hx line 1075
Called from as3hx/Parser.hx line 1179
Called from as3hx/Parser.hx line 330
Called from as3hx/Parser.hx line 1003
Uncaught exception - In C:/Users/MikeC/Desktop/as3hx/robotlegs2/src/robotlegs/bender/extensions/eventCommandMap/impl/Eve
ntCommandTrigger.as(75) : Unexpected .

[/codesyntax]

It seems like as3hx is getting confused around this line in the AS3 source:

[codesyntax lang="actionscript" lines="normal"]
if (describeType(mapping.commandClass).factory.method.(@name == "execute").length() == 0)
throw new Error("Command Class must expose an execute method");

[/codesyntax]

It looks like a bit of E4X is confusing the script. To solve this sort of problem I made a note of the location and file and just commented the offending line out. This allows as3hx to get past that particular snag. After going through this process a few times the project should be fully converted.

From there I setup a project in FlashDevelop and tried to compile. After fixing a few things that as3hx couldnt solve I came accross a rather major stumbling block.

RobotLegs2 unlike RL1 has a strong dependency on the dependency injection container SwiftSuspenders. So to get RL to compile I first need to port SwiftSupenders2.

So I repeated the process above but for SwiftSuspenders. Eventually this left me with a whole load of broken unit tests. Till Schneidereit the (rather splendid) author of SwiftSuspenders wrote a great number of unit tests for the library, which is one of the reasons why its so excellent. So I knew that to achieve a proper port all I need do is pass all those tests and I can then be confident that the code is solid.

After a few evenings of toil I managed to get 50 tests to pass in the Flash target. This is quite abit shy of the 160+ tests in the original AS3 version of the library, however a great many of those tests are not relevant to Haxe such as ArrayCollection tests, XML tests and DescribeType tests. I also decided for now to remove all of the event dispatching (and thus their tests) code from the library for now due to their dependency on the Flash platform. Despite this I think the 50 tests that do pass are probably representative of the core functionality of the library.

With the Flash target passing I indented to then move onto passing the tests in the other targets (JS, C++, php etc). I was hoping that with the flash part passing that they would all pass considering that im using the inbuilt haxe reflection methods not any platform specific reflection, but alas this was not to be the case. Starting with the JS target I started to get alot of errors on some of the basic Injector tests. After some digging in the compiled JS source I traced it back to an issue in the Meta Data generation for the @Inject tag on the JS target.

Unfortunately, I have run out of time on this little side project for now so am going to have to park it. I have uploaded the progress thus far to GitHub should anyone else wish to take up the mantle on the port:

https://github.com/mikecann/SwiftSuspendersHx
https://github.com/mikecann/RobotLegs2Hx

I had indented, once everything was passing, was to do a branch of the project and incorporate some features that only the Haxe language can support. Features such as proper generics and macros would bring some added awesome.

Wednesday, 4 April 2012

Introducing Printomi


I'm extremely proud to announce the launch of a project I have been working on for quite a while now.


Printomi is a service for social games that allows players to take snapshots of their worlds and upload them to their own personal gallery. Players can like, comment share and order poster prints of their virtual creations.


The way it works is we provide the game owner with a tiny API that is used to interface with Printomi. The bulk of the Printomi client is downloaded at runtime from the Printomi servers. This is good for two reasons. Firstly by keeping down the size of the code that must be embedded into the game we can keep down the initial load time the player must sit through before they can play the game. Secondly we can upload changes and fixes to Printomi without requiring the game owner to recompile their code.


Once downloaded the printomi client is ready to be be used. In the case of Gourmet Ranch a themed button is shown to the player inviting them to click:



Once clicked (or activated by the JavaScript API) the main Printomi window opens:



The window has controls to zoom in and move the print about allowing the player to get the perfect angle of their world:



Once happy the player can then saves the print to the printomi servers. While the image is uploading the user can continue to play the game. Once the upload is complete the window is opened once more offering to show the player their print.



Printomi is tightly integrated with Facebook so that it's as easy as possible for new users to get started:



Once connected the new print is then available for viewing, sharing, liking, commenting, etc:



In addition the prints are organised into galleries so that users can browse the uploads of others:



If a user particularly likes one print then they can order it as a poster:



Currently we only offer posters to people living in the US however we plan on opening it up to other countries when we can.


To print to such a large poster (24x18" @ 150DPI) and maintain the quality of the final product we must capture a large number of pixels. For example here is a comparison between what a user would see on printomi.com and what we store behind the scenes:



The technology that lets us capture these large images and store them in a compressed way (to conserve disk space and therefore cost) is quite complex and will have to wait for a later post.


Printomi is currently only available to a small subset of the Gourmet Ranch user base but we are performing a steady-rollout to everyone, so if you don't have access to the button in Gourmet Ranch just yet then don't worry it should be available for you soon!


Printomi is a culmination of many many hours of hard work, late nights and stress. But its been worth it! I've had a blast throughout the whole process and am proud of the result. I have also learnt a whole bunch in the process. I have had to work with so many technologies to pull this off, to name a few: AS3, C++, C#, ASP.Net, MySQL, IIS, AWS. I have particularly enjoyed the C# work having largely abandoned the language since my early work with it.



If you would like to support me or if you would like to keep up to date with the goings on with Printomi then you can like us on Facebook or follow us on Twitter :)


Monday, 12 March 2012

Try { Harder } 2012 Levelup



Last year I was fortunate to be one of the lucky 16 to attend the first try { harder } experimental conference / coder retreat in Nottingham. As mentioned in my blog post at the time it was an incredible 4-day event in which I learnt so much from some of the most talented and experienced people in the flash community.

The event was such a success that not only is it going to run again this year (which I hope very much to attend) but there is also an additional "levelup" conference happening next week. The idea behind the levelup is to provide businesses and freelancers with an intensive 4-day training and motoring session. The mentors are hand picked from the previous try harder members and so represent some of the best in their field.

What's more Stray, the primary organiser of the event has just announced that Jetbrains the makers of the popular IntelliJ IDEA IDE are going to be sponsoring the event meaning each paying participant will receive a licence to use the IDE!

Interested? Head over to the levelup site and sign up: http://www.tryharder.org.uk/level-up-2012/

 

Sunday, 28 November 2010

Multi-Line Flex Label [MXML]

Just stumbled across this one while writing some mxml for a personal project and thought I would share.

Have you ever wanted to have multi-line text in your label component in spark and thought the following should work?

[codesyntax lang="mxml"]
<s:Label text="I like text on the \n next line" />

[/codesyntax]

But all it produces is:



Yep me too.

After some playing however I stumbled accross the following solution:

[codesyntax lang="mxml"]
<s:Label text="I like text on the {'\n'} next line" />

[/codesyntax]

It then produces the expected result:



Im just guessing but I suspect its something to do with the black art of the flex life cycle. By adding the {'\n'} we are turning the property initialisation on the label component from a simple literal assignment into a delayed binding assignment and therefore gets parsed differently.

Just a guess, let me know if im way off.

Saturday, 23 October 2010

Inputtie Development History - Networking

This is part two in my series of posts on the development history of Inputtie.

In this post I talk about the challenge of device discovery and networking in the Inputtie app.

Zero Configure Networking

I knew I wanted Inputtie to be as simple to get running as simply starting it up. For this to happen Inputtie would need to discover all other devices on the network also running Inputtie. So how to do this?



Well, as it happened I had been reading at the time about Apple's Bonjour which was designed to do just what I needed. It is a combination of a multi-cast and DNS lookup service that allows it to detect other Bonjour capable devices on the network. Sounds perfect.

So I got to work on implementing their Java API. After many trials and tribulations I eventually had it working.. kinda. It was detecting other devices sure, but every now and then it would sporadically disconnect from the network. I couldn't for the life of me work out why. I posted on forums and even tried to read the reams of source to see what was going on but alas to no avail.

After much deliberation I decided to look for another solution to the problem of Zero Conf. networking. Next up were a whole host of other attempts. I tried JmDNS which is was supposedly very similar to Bonjour. I also experimented with JGroups. I had limited success with all of them and in the end only really succeeded in wasting several months worth of development time.

The Solution

In the end the solution (and the one currently employed in Inputtie) was the simplest. After months of messing around with these libraries I had learnt quite abit about how they performed their magic. At the heart of it they either used multi-cast or broadcasting to announce a device on a network. Broadcasting can be thought of as a sort of sonar pulse. The broadcasting computer sends a message on a specific IP address then another device listens for the message and proceeds to open a Socket for a more private form of communication. From Wikipedia:
A broadcast address is a logical address at which all devices connected to a multiple-access communications network are enabled to receive datagrams. A message sent to a broadcast address is typically received by all network-attached hosts, rather than by a specific host.

I decided that if these libraries could use broadcasting for discovery then so could I and if I wrote it myself I could keep it simple. So I set to work coding an example in Java. In no time at all I had it running and surprisingly it worked! Sure it wasnt as robust as the established libraries, it didn't handle devices disconnecting from the network, different network subnets or IPv6 but it was simple and at least it worked!

Broadcasting in Adobe AIR

As I mentioned in a previous post Inputtie went through many re-writes during development from its original form in Java through C++, C Sharp and finally Adobe AIR. With the latest (it was still in beta when I started development) version of Adobe AIR 2.0 several new APIs were made available for use, one of them being new classes designed specifically for peer to peer (P2P) networking. With these new APIs I believed I should be able to implement network broadcasting much in the same was I was doing in Java. Unfortunately however it seemed that Adobe was restricting the use of broadcast to their new P2P service Cirrus.

There was however another crucial API released with AIR 2.0; the NativeProcess API. With this a developer is able to easily execute and communicate with a program written in another language. What this meant for Inputtie was that I could write the user interface in AIR and then use NativeProcess to call Java code that would perform actions not available in AIR, such as Broadcasting. (incidentally it also is a great way to do multi-threading in Air ;))

So the current solution in Inputtie is to use NativeProcess from AIR to communicate with a small headless (no user-interface) Java process that does the broadcasting and listening for broadcasts. Once the Java process detects an incoming broadcast it passes the information back to AIR.

EDIT: If anyone is interested in seeing the source to my previous (failed) attempt just drop me a comment or an email and I would be happy to share.

Monday, 16 August 2010

AS3, Dictionary & Weak Method Closures

This is going to be a technical post so those of you not of the code persuasion look away now..

Okay great, now those guys have gone I can get down to it.

Some of my recent work on the SWFt project has revolved around the use of Robert Penners AS3Signals. If you dont know what Signals are I strongly reccomend that you check out Roberts blog for more info. In brief, they are an alternative to the Events system found in Flash, based on the Signal / Slot pattern of Qt and C# they are much faster and more elegant (my opinion) than native events.

I have been trying to incorporate signals in SWft for both the elegance and performance gains that they bring, however there is an issue that was brought to my attention by Shaun Smith on the mailing list. The issue is that my current use of them will cause memory leaks.

I realised that this too would apply to the work I had been doing using the RobotLegs and Signals libraries. RobotLegs (for those of you that dont know) is an excellent Dependency Injection framework inspired by the very popular PureMVC framework. I have blogged before about its excellence. Signals have been incorporated into RobotLegs as a separate 'plugin' by Joel Hooks in the form of the SignalCommandMap. The SignalCommandMap does as the name implies, it allows you to map signals to commands so that whenever a mapped signal is dispatched then the corresponding command is executed.

Its a very nice, elegant, solution to RIA development. However there is one catch. I have so far been using signals such as:

[codesyntax lang="actionscript3" lines="normal"]
public class MyMediator extends Mediator
{
// View
[Inject] public var view : MyView;

// Signals
[Inject] public var eventOccured : ViewEventOccuredSignal;
[Inject] public var modelChanged : ModelChangedSignal;

override public function onRegister():void
{
view.someSignal.add(eventOccured.dispatch);
modelChanged.add(onModelChanged);
}

protected function onModelChanged()
{
view.updateView();
}
}

[/codesyntax]

So here we can see a typical use of Signals in a mediator. There are two things going on here that are of concern, lets break them down.

Firstly on line 12 we are listening to a signal on the view, then passing on the event directly to an app-level event, notice how nice and clean this is, this is what I love about using RL & Signals. Line 13 we are listening for an app-level signal for a change on the model then updating the view to reflect this.

It all looks well and good but unfortunately in its current state it could cause a memory leak. This is because we are listening to events on signals without then removing the listen. For example, we are listening to the app-level event on line 13 "modelChanged.add(onModelChanged);" so now the "modelChanged" signal has a reference to this Mediator. This will cause a leak when the View is removed from the display list. Normally the mediator would also be make available for garbage collection, however, because the singleton Signal has a reference to the Mediator it cannot be removed.

The same goes for line 12. Suppose the "ViewEventOccuredSignal" that is injected is not a singleton and is swapped out for another instance it could not be garbage collected as the "view.someSignal" has a reference to its dispatch function.

Realising this problem I knew that the solution was simply to be careful and add a "onRemoved" override function in my Mediator then clean up by removing the signal listeners. However I like the simplicity and beauty of current way of doing things so I started to wonder if there was another way.

I started thinking about whether I could use weak references with the Signal. If I could then I wouldnt have to worry about cleaning up as the Signal wouldnt store any hard-references to the functions and so the listener would be free for collection. After some digging however I realised that there was no option for weak listening in Robert Penners AS3Signals.

I thought to myself why the hell not? I knew that the Dictionary object in AS3 has an option to store its contents weakly so I thought so long as you don't require order dependant execution of your listeners it should be possible to store the listener functions in a weakly referenced Dictionary.

It was at this point that I noticed Roberts post on the subject of weakly referenced Signals: http://flashblog.robertpenner.com/2009/09/as3-events-7-things-ive-learned-from.html. In it he references Grant Skinners post concerning a bug with storing functions in a weakly referenced Dictionary.

From Grant's post:
Note that there is a known bug with Dictionary that prevents it from operating correctly with references to methods. It seems that Dictionary does not resolve the method reference properly, and uses the closure object (ie. the "behind the scenes" object that facilitates method closure by maintaining a reference back to the method and its scope) instead of the function as the key. This causes two problems: the reference is immediately available for collection in a weak Dictionary (because while the method is still referenced, the closure object is not), and it can create duplicate entries if you add the same method twice. This can cause some big problems for things like doLater queues.

This was starting to look bad for my idea. Me being me however, I thought I knew better, and that post was written pre Flash 10 so I thought to myself: perhaps its been fixed in Flash 10. So I set to work coding a simple example.

I created a very simple Signal dispatcher:

[codesyntax lang="actionscript3" lines="normal"]
package
{
import flash.events.EventDispatcher;
import flash.utils.Dictionary;

public class SimpleDispatcher
{
protected var _listeners : Dictionary;

public function SimpleDispatcher(useWeak:Boolean)
{
_listeners = new Dictionary(useWeak);
}

public function add(f:Function) : void
{
_listeners[f] = true;
}

public function dispatch() : void
{
for (var o:* in _listeners)
{
o();
}
}
}
}

[/codesyntax]

And a very simple listening object:

[codesyntax lang="actionscript3" lines="normal"]
package
{
public class SimpleListener
{
public function listen(d:SimpleDispatcher) : void
{
d.add(onPing);
}

protected function onPing() : void
{
trace(this+" - ping");
}
}
}

[/codesyntax]

And then a simple Application to hook it all together:

[codesyntax lang="mxml" lines="normal"]
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">

<fx:Script>
<![CDATA[
import mx.controls.List;

protected var _dispatcher : SimpleDispatcher = new SimpleDispatcher(true);
protected var _listener : SimpleListener;

protected function onAddListenerClicked(event:MouseEvent):void
{
_listener = new SimpleListener();
_listener.listen(_dispatcher);
}

protected function onRunGCClicked(event:MouseEvent):void
{
try
{
new LocalConnection().connect('foo');
new LocalConnection().connect('foo');
}
catch (e:*) {}
}

protected function onDispatchClicked(event:MouseEvent):void
{
_dispatcher.dispatch();
}

]]>
</fx:Script>

<s:VGroup width="100%" height="100%" horizontalAlign="center" verticalAlign="middle">
<s:Button label="Add Listener" click="onAddListenerClicked(event)" />
<s:Button label="Run GC" click="onRunGCClicked(event)" />
<s:Button label="Dispatch" click="onDispatchClicked(event)" />
</s:VGroup>

</s:Application>

[/codesyntax]

So what I should expect to see from this example is that when I click "Add Listener" it should create a listener reference which will then listen for when the signal is dispatched and trace out a "ping".

What actually happens is you get nothing. No trace out, despite the fact that there is clearly still a reference to the listener in the Application file.

So whats happening here? If you break into the debugger at the point that the listener is added then you get the following:



You can see that the type "MethodClosure" is added as the key to the dictionary rather than Function which is passed in. MethodClosure is a special native Flash Type that you dont have access to. It exists to resolve the issues we used to have in AS2 where passing a function of a class to a listener would cause the listener to go out of scope and other nasties. From the Adobe docs:
Event handling is simplified in ActionScript 3.0 thanks to method closures, which provide built-in event delegation. In ActionScript 2.0, a closure would not remember what object instance it was extracted from, leading to unexpected behavior when the closure was invoked.

..
This class is no longer needed because in ActionScript 3.0, a method closure will be generated when someMethod is referenced. The method closure will automatically remember its original object instance.

The only problem is that it seems that using a MethodClosure as a key in a weak dictionary causes the MethodClosure to have no references and hence be free for garbage collection as soon as its added to the Dictionary which is not good :(

So thats about as far as I got, I have spent a few evenings on this one now and I think im about ready to call it quits. I had a few ideas about creating Delegate handlers to make functions very much in the same way as was done in AS2 but then I read this post: http://blog.betabong.com/2008/09/26/weak-method-closure/ and the subsequent comments and realised it probably wasnt going to work.

I also had an idea about using the only other method of holding weak references the EventDispatcher class. I thought perhaps somehow I could get it to hold the weak references then I could loop through the listeners in there calling dispatch manually. Despite "listeners" property showing up in the Flex debugger for an EventDispatcher you dont actually have access to that property unfortunately so hence cant get access to the listening functions. Interestingly however the EventDispatcher uses "WeakMethodClosure" object instead of the "MethodClosure" object according to the debugger.

Well I guess for now Ill have to make sure I code more carefully and unlisten from my Signals ;)