AS4 Wish: Shorthand Eventing with Flows
One thing I love and hate about ActionScript 3 is the eventing model. I love the departure from AS2 type callbacks. And I love the way it allows me to have loosely coupled classes. Anyway, to rephrase and refrain from stating the obvious, I think eventing is awesome.
But after the AS3 honeymoon … … I resent the number of times a day I find myself typing out object.addEventListener(…,…) and then object.removeEventListener(…,…). I resent it even more when I know that the event shall only happen once, normally for some kind of COMPLETE event; thus making the first line of my handler always be IEventDispatcher(e.target).removeEventListener(e.type,…). It’s just too verbose, especially when it’s such a core feature of ActionScript.
Now, I’m not trying to crawl onto the recent AS3 is harder and takes longer bandwagon here. I’m ecstatic that AS2 is not longer a daily thing for me; I wouldn’t even go back to it for a pay-rise. But, I feel something could be added to AS3 to make eventing less verbose and less prone to things such as memory leaks.
What makes eventing so verbose? Well, for every event we want to subscribe to, we do:
1) Add Listener
object.addEventListener(”eventtype”, eventHandler);
2) Create a function to handle that event
private function eventHandler(e:Event):void {
trace(”hello world”)
}
3) Remove Listener
object.removeEventListener(”eventtype”, eventHandler);
The creation of a handler function per event group is something that especially rubs me the wrong way, but when working in an asynchronous language, what else can you do? I propose a new concept called a “Flow”. A Flow mimics the blocking nature of synchronous languages while keeping inline with the asynchronous environment of ActionScript.
To outline my proposal, I’m only going to give a commented example, but I hope from it you’ll be able to take away the key concepts. And I stress concepts! As this probably won’t be the best syntactic solution.
class FlickrPhotoGizmo extends EventDispatcher {
// Note that this is a "flow" and not a function.
// Flows seem to be able to "block" until a matching event type is dispatched
// Flows work with existing AS3 code .. ie. imageLoader.addEventListener(Event.COMPLETE, ...)
// A flow will always dispatch a "FlowEvent" of constant type on return.
// Flows are a one time deal; no need to keep listeners around once completed.
// Null returns shall be detailed in the "FlowEvent" for later inspection.
// The "->" notation is our "syntax sugar"
public flow loadAndFilterImage(searchTerm:String):BitmapData {
var imageLoader:FlickrLoader = new FlickrLoader();
var imageFilter:ImageFilter = new ImageFilter()
var resultBitmap:BitmapData;
imageLoader.getMostPopular(searchTerm) -> {
Event.COMPLETE -> resultBitmap = imageLoader.bitmapData;
Event.NO_MATCH -> return null;
}
imageFilter.filter(resultBitmap) -> {
Event.COMPLETE -> {
resultBitmap = imageFilter.filteredBitmapData;
imageFilter.fooClean()
}
Event.ERROR -> return null;
}
imageFilter.filter2(resultBitmap)
-> Event.COMPLETE
-> resultBitmap = imageFilter.filteredBitmapData;
return resultBitmap;
}
}
// wrapper app
funtion init():void {
var gizmo:FlickrPhotoGizmo = new FlickrPhotoGizmo();
// let's load an image with happy people, then filter it...
// ... then give the result to the "imageReady" function
// remember: this is a one time "FlowEvent" event that results from a "flow"
gizmo.loadAndFilterImage("happy people") -> imageReady;
addPermEventHandlers();
}
function imageReady(e:FlowEvent):void {
// no need to call removeEventListener as this is a one time event
var image:BitmapData = e.yield;
if (image) {
addChild(new Bitmap(image))
} else {
var errorEvent:Event = e.nullEvent
switch (errorEvent.type) {
case Event.NO_MATCH: trace("no happy people found :(")
}
}
removePermEventHandlers();
}
// maybe we want this new syntax for permanent listeners too .. note: "o"
// (i know "o" might be a bad pick .. but just go with it)
function addPermEventHandlers {
o-> MouseEvent.UP -> mouseUpHandler
stage o-> KeyboardEvent.UP -> keyPressHandler
}
// and because we have permeant listeners, we need to be able to remove them .. note: "<"
function removePermEventHandlers {
o<- MouseEvent.UP -> mouseUpHandler
stage o<- KeyboardEvent.UP -> keyPressHandler
}
function mouseUpHandler(e:MouseEvent):void {
trace("we're still loading that image for you, just wait .. blame Flickr")
if (false && "anotherExample") {
// this is short hand for .. this o<- MouseEvent.UP -> mouseUpHandler
// we're able to do it because we're aware of the context
o<-e
}
}
function keyPressHandler(e:KeyboardEvent):void {
}
Comments(10)


