Thursday, March 4, 2010

closures in actionscript

From time to time, I've read that you can use closures in Actionscript, but I've never found a use for them until now. Before I explain that use, let me go over what closures are and how they work.

Normally, local variables die after functions are through running:


function someFunction() : void
{
var myFriend : String = "Fred";
}

someFunction();
trace( myFriend ); //1120: Access of undefined property myFriend.


But things get wacky when functions return other functions:


function functionMaker() : Function
{
return function() : void { trace ( "I am a new function!" ) }
}


In the above example, I haven't used any variables. I'll add one shortly. For now, just note that functionMaker's return type is Function and that it, in fact, does return a function. The function it returns in anonymous. That is, it doesn't have a name. We can access it this way:


var aNewFunction : Function = functionMaker();
aNewFunction(); //I am a new function!


functionMaker returns a new (anonymous) function, which we stored in a variable called aNewFunction. We then called the function stored in aNewFunction by following the variable's name with the call operator: ().

You can shorten the above to...

functionMaker()();

That looks odd, but it works. The first call operator calls functionMaker; the second class the function that functionMaker returns.

Let's take another look at the guts of functionMaker:


function functionMaker() : Function
{
return function() : void { trace ( "I am a new function!" ) }
}


From now on, in the case of functions that return other functions, I'm going to call the main function the outer function and the returned function the inner function:


//outer function
function functionMaker() : Function
{
//inner function
return function() : void { trace ( "I am a new function!" ) }
}


What happens if we create a local variable in the outer function and try to reference it from the main body of our code?


function functionMaker() : Function
{
var food : String = "cheese"?

return function() : void { trace ( "I am a new function!" ) }
}

functionMaker();
trace( food ); //1120: Access of undefined property food.


No surprise. food is a local variable to functionMaker. We can't access it from outside the function. However, what if we try to access it from within the inner function?


function functionMaker() : Function
{
var food : String = "cheese"?

return function() : void { trace ( "I am a new function, and I love " + food + "!" ) }
}

var aNewFunction : Function = functionMaker();
aNewFunction(); //I am a new function, and I love cheese!


Take a moment to think about what just happened. When we ran the inner function, it spit out the word "cheese" as part of its output, even though that word wasn't stored inside it. It got that word by referencing the outer function's variable. So inner functions have references to the variables in their parent functions.

Now take a closer look at these lines:

1. var aNewFunction : Function = functionMaker();
2. aNewFunction(); //I am a new function, and I love cheese!

functionMaker, the function that contains the value "cheese" finishes running on line one, so under normal circumstances, cheese should be dead by line two. But it's not. And that, kids, is a closure: inner functions have access to the variables in their parent, outer functions even after those outer functions have stopped running!

Not only can they access those variables, they can alter them!


function functionMaker() : Function
{
var food : String = "cheese"?

return function() : void { food += " crackers"; trace( "I am a new function, and I love " + food + "!" ) }
}

var aNewFunction : Function = functionMaker();
aNewFunction(); //I am a new function, and I love cheese crackers!


There's one last key aspect of closers I haven't explained: From the inner-function's point-of-view, the variable is static. That is, it keeps its value even after the inner function is done running! That means that each time you call the inner function, it can access the last value stores in the variable.


function counterMaker() : Function
{
var count : int = 0;

return function() : void { trace( count ++ ) }
}

var aNewCounter = counterMaker();
aNewCounter(); //0
aNewCounter(); //1
aNewCounter(); //2
aNewCounter(); //3


Compare this with a stand-alone version of the inner function:


function counter() : void
{
var count : int = 0;
trace( count++ );
}

counter(); //0
counter(); //0
counter(); //0
counter(); //0


In the stand-alone version, the variable counter gets reset to zero each time the function is called. It gets incremented in the trace, but by then it's too late. The function is over and its local variable dies. We can use closures to add static variables to functions!

As I said at the top of this article, I had read about closers for years, but I didn't see how they were useful in Actionsctipt, which is an object-oriented language. As such, if I wanted a counter with a static variable, I would make and use one like this:


public class Counter
{
private var _count : int = 0;

public function next() : { trace( _count++ ) }
}

var counter : Counter = new Counter();
counter.next(); //0
counter.next(); //1
counter.next(); //2
counter.next(); //3


So what made me suddenly want to use a closure? Well, I was trying to do something very specific involving regular expressions. I started with this text:

Photo is of a sunset.
Photo is of my sister.
Photo is of a horse.
Photo is of a birthday party.
... [many other similar lines]
Photo is of a calm lake near the city.

From that, I wanted to output...

Photo1 is of a sunset.
Photo2 is of my sister.
Photo3 is of a horse.
Photo4 is of a birthday party.
... [many other similar lines]
Photo[n] is of a calm lake near the city.

...with each new "Photo" getting an incremented number appended to it.

To start out with a simpler example, let's say that I didn't care about the numbers incrementing. I just want a random number appended to the end of each "Photo" (Photo2, Photo9, Photo3, etc.).


var text : String = "";
text += "Photo is of a sunset.";
text += "Photo is of my sister.";
text += "Photo is of a horse.";
text += "Photo is of a birthday party.";
text += "Photo is of a calm lake near the city.";

var regExp : RegExp = new RegExp( "Photo", "g" );

text = text.replace( regExp, String( Math.round( Math.random() * 10 ) );
trace( text );


That doesn't get me exactly what I want. It doesn't append a random number onto the end of each "Photo". Instead, it replaces each "Photo" with a random number:

6 is of a sunset.
0 is of my sister.
10 is of a horse.
6 is of a birthday party.
3 is of a calm lake near the city.

I could prepend the original string "Photo" onto the random number ...

text = text.replace( regExp, "Photo" + Math.round( Math.random() * 10 );

... but that second parameter is starting to get long, ugly and unreadable. Luckily, the String.replace() method accepts a function as its second parameter:


function appendRandomNumber() : String
{
return arguments[ 0 ] + Math.round( Math.random() * 10 );
}

var regExp : RegExp = new RegExp( "Photo", "g" );

text = text.replace( regExp, appendRandomNumber );
trace( text );


What happens here is that replace calls the appendRandomNumber method, handing it an array, which the function receives in a variable called arguments. If you want to know everything that's stored in the array, look up String.replace() in help. All we care about here is arguments[0], which contains whatever the regular expression matched: in this case, the word "Photo." The function returns that plus a random number:

Photo4 is of a sunset.
Photo7 is of my sister.
Photo0 is of a horse.
Photo10 is of a birthday party.
Photo6 is of a calm lake near the city.

Putting that idea together with closures, we can hand String.replace() an inner function that uses its parent's static variable to keep count:


function counterAppenderMaker() : Function
{
var counter : int = 1;

return function() : String { return arguments[0] + counter++ }
}

var regExp : RegExp = new RegExp( "Photo", "g" );

text = text.replace( regExp, counterAppenderMaker() );
trace( text );


Which yields this output:

Photo1 is of a sunset.
Photo2 is of my sister.
Photo3 is of a horse.
Photo4 is of a birthday party.
Photo5 is of a calm lake near the city.

I think this is an elegant solution. To be fair to OOP, there is another way of doing this:


public class AppendCounter
{
private var _counter : int = 1;

public function doIt() : String
{
return return arguments[0] + _counter++;
}
}

var regExp : RegExp = new RegExp( "Photo", "g" );
var appendCounter : AppendCounter = new AppendCounter();

text = text.replace( regExp, appendCounter.doIt );
trace( text );


I am not advocating closures over objects (or vice versa), but it's nice to know the closure method. Depending on what I'm trying to achieve, it may be clearer to have all the logic in one class rather than referencing a second class (or a global variable) just to increment a counter.

Thursday, January 21, 2010

subtleties

Whew! I just finished a hell of a debugging session. My goal was to make Flash submit a url to tinyurl.com for minification.

My code worked locally (when I ran the swf on my desktop), but it didn't work in the browser. So I was pretty sure it was a security issue. But I couldn't understand why I wasn't getting a response from http://tinyurl.com, because they DO have a crossdomain.xml file. See: http://www.tinyurl.com/crossdomain.xml

hint: if you're smarter than I am, you may be able to guess the problem just via the previous paragraph.

Here's the code that didn't work:


send();

function send() : void
{
var url : String = "http://www.google.com/search?q=cows";
var urlLoader : URLLoader = new URLLoader();
urlLoader.addEventListener( Event.COMPLETE, receive );
urlLoader.load( new URLRequest( "http://www.tinyurl.com/api-create.php?url=" + url ) );
}

//this callback function never gets called!
function receive( event : Event ) : void
{
var urlLoader : URLLoader = event.target as URLLoader;
//output is a text field on the stage
output.text = urlLoader.data;
}


Here's the working version. Can you spot the difference?


send();

function send() : void
{
var url : String = "http://www.google.com/search?q=cows";
var urlLoader : URLLoader = new URLLoader();
urlLoader.addEventListener( Event.COMPLETE, receive );
urlLoader.load( new URLRequest( "http://tinyurl.com/api-create.php?url=" + url ) );
}

function receive( event : Event ) : void
{
var urlLoader : URLLoader = event.target as URLLoader;
//output is a text field on the stage
output.text = urlLoader.data;
}


Give up? The difference is in this statement:

BUGGY: urlLoader.load( new URLRequest( "http://www.tinyurl.com/api-create.php?url=" + url ) );

WORKING: urlLoader.load( new URLRequest( "http://tinyurl.com/api-create.php?url=" + url ) );

In case you still don't see it, the buggy version has a www in-front-of the url and the working version doesn't.

tinyurl's crossdomain.xml file is located at http://tinyurl.com/crossdomain.xml NOT http://www.tinyurl.com/crossdomain.xml.

But you'll get to it if you type it the "wrong" way into the browser, because most browser normalize urls. Flash doesn't. To Flash, there is no crossdomain.xml file, because it was specifically looking for one at the www address, and there isn't one there.

The scary thing is that my FIRST assumption was that it was a crossdomain.xml issue, so I watched the Activity Window in Safari as I ran my app (the bad version) in the browser. The Activity window showed that the crossdomain file was being accessed correctly. But apparently that was just the BROWSER accessing it correctly. Flash still thought of it as a bogus file, since it came from a www site.

Thursday, January 14, 2010

how long is an mp3?

I need to know the length (in seconds) of a progressive mp3 before it starts playing. As-far-as I can tell, there are only three ways of getting this information:

1) if it's explicitly stated in some sort of data feed (e.g. an XML playlist), you can, of course, grab that info and hope it's accurate.

2) you can read it from the id3 tags -- the metadata embedded in the mp3 file itself -- and hope THAT'S accurate.

3) you can guestimate length using some simple math.

Option one won't work for me, because my clients are generally not going to enter durations into a data feed.

I spent hours trying to get option two to work, emailing other developers and asking them for advice. I wasn't receiving the id3 data. Someone mentioned to me that I was likely hitting a security wall. It turns out that though a SWF can play mp3s from another domain, it can't access embedded id3 data without permission. See: http://kb2.adobe.com/cps/963/50c96388.html

I figured this was the problem, so I added a crossdomain file and a SoundLoaderContext object to Sound.load(), but I still didn't receive any id3 data. Why? Because there wasn't id3 data in the mp3s I was using -- even though the client assured me that there was.

I realized that I can't count on there being id3 data. Even if there is, there may not be length data, as it's optional which id3 tags are included in an mp3 file (or if any are included at all).

Which lead me to try option three. I patched it together based on various similar solutions I found online:

This code runs in a loop:


if( _duration == 0 && ( bytesLoaded / bytesTotal ) > 0.1)
{
_duration = _sound.length / 1000 / bytesLoaded * bytesTotal;
}


It waits until ten percent (0.1) of the mp3 is cashed and then calculates duration. It's an estimate, because it's based on Sound.length, which is NOT necessarily the length of the whole mp3. It's the length of what's loaded so far.

And you can't simply guess the length from bytesTotal, because depending on the compression/bitrate of the mp3, the same number of bytes could mean different lengths. So the calculation takes into account the known length, the number of bytes loaded so far and the total number of bytes. (Divided by 1000 to convert from milliseconds to seconds.)

How much should I cache before I let Flash do the calculation? Is ten percent enough? (The JW Player uses ten percent.) I tried it with an mp3 which I knew to be 1 minute and 2 seconds. The guestimation was close but not perfect: 00:59 and 1:00 on subsequent runs.

I upped the cached-percent to 0.2, which produced perfect guesses. Also, on my high-bandwidth (but not exceptionally high-bandwidth) connection, it took about a second for 0.2 percent to cache, which is acceptable for my purposes.

But then I tried a one-hour-long mp3. As you might expect, it took quite some time for 20 percent to cache. Totally unacceptable. I changed the percent back to 0.1 and the hour-long mp3 produced a guess in a reasonable amount of time (it took about fifteen seconds to guess). And the guess was only off by one second.

In the end, I am probably going to use a three-pronged approach: first, I will check for duration data in the XML feed, using that if it's there (doubtful). Next, I will try to use id3 data. Failing both those approaches, I will guestimate with a ten-percent cache.

If anyone reading this has a better idea, please let me know!

I am also trying to figure out how to adjust the UI if Flash has to guestimate. When the hour-long mp3 finished playing, the time-duration display said 00:59:00/1:00:00, which doesn't thrill me. Should I fudge the time up to the duration? (if end_time != duratation; then end_time = duration.)

Someone suggested that I keep checking for duration and adjust it as it the guess gets more accurate (which it will as more data gets cached.) I don't know. I think it would be pretty distracting seeing the the duration-readout change. Also, my played-progress bar would jump around, popping to a longer or shorter width.

What do you think?

Friday, November 13, 2009

rethinking constructors -- or what I learned from objective-c

Like many Flash developers, I've been studying Objective-C in a desperate attempt to ride the iPhone app train. (Though I think it left the station while I was still putting a token in the turnstile.)

One thing I like about Objective-C is its version of constructors, which usually start with the word "init." For instance, a method might be called just init(), or, if it takes arguments, it might be called initWithColor( 0xFF000 ) or initWithColorAndType( 0xFF0000, "large" );

Note: objective-C's syntax is different from Actionscript's, so in reality, the last method call above would look like this: [myObject initWithColor: 0xFF0000 andType: @"large"]; Since this post is about Actionscript, I'll keep everything in AS syntax.

You can, in a sense, overload Objective-C constructors. A class can't have two init() methods. But it can have init(), initWithColor() and initWithColorAndType(). You call the appropriate one, depending on how you want to initialize the object.

I also like the fact that every Objective-C class has a formal interface (defined in its header file). I do that for my Actionscript classes, too.

All of my classes (except DTOs and utilities with static members) implement at least one interface. Often, several classes will share the same interface. But even if a class is a loner, I make an interface file for it. I like this this clean separation between interface and implementation. When you browse my code, you can learn how everything fits together just by reading the interface files.

But you can't define constructors in an interface! That bothers me, because a constructor is -- or can be -- a way of communicating with a class. And if something is part of the way one communicates with a class, it is, by definition, part of that class's interface.

(I can't use my TV until I first turn it on. So the power button is kind of like a constructor. But it would be insane to say that the power button is not part of the TV's interface.)

Traditionally, interface files are only used when they are meant to be shared by multiple classes. In that sense, I get why they can't include constructors. Class A and Class B can't share a constructor, because Class A's constructor must be named A() and Class B's must be named B().

But since I make separate interface files for each class, I'd like to list ALL class inputs and outputs in those interface files.

Here's my solution: I never pass ANYTHING into a constructor. In other words, I would never write a constructor like this:

public function Person( name : String ) { ... }

Instead, person's constructor will look like this:

public function Person() { ... }

I don't care that the Person() method can't be listed in an interface file. It's not used as an interface element. It doesn't suck anything in from the outside world.

That's not to say I won't write a constructor function. I will if the class has any internal housekeeping it needs to do at start-up:

public function Person()
{
_kids = new Array();
}

So how do I specify that this a Person is named "George"?

var dad : Person = new Person();
dad.initWithName( "George" );

If it's also legal to have a nameless person, I would write this:

var dad : Person = new Person();
person.init();

All my classes have at least an init() method, even if it is just a placeholder husk. Want to know if my classes can be initialized any other way? Just check their interfaces:

public class Person implements ILifeform...

public interface ILifeform
{
function init() : void;
function initWithName( name : String ) : void;
function initWithNameAndGender( name : String, isMale : Boolean );
function eat() : void;
function die() : void;
function die() : void;
function addKid( name : String ) : void;
}

One objection to my system might be that initializer-method names could get absurdly long:

initWithWarpDriveShieldsPhotonTorpedosHoloDecksAndTransporters( ... );

To me, that's not an objection -- it's a warning! Even without my system, I would never write code like this:

var myShip : SpaceShip = new SpaceShip( true, false, true, true, false );

The more arguments a method takes in, the harder the code is for me to read, and the more apt I am to make a mistake. I have a loose rule of thumb that methods should take in no more than three arguments (and three is really pushing it).

So I'd change the above long init method to this:

initWithSpecs( specs : SpaceShipSpecs );

And I'd back this up with DTO class called ShipSpecs that had properties like warpDrive, sheilds, etc.

three little tricks

Here are a couple of tricks I learned form this article:

I try never to access an array's length in a for loop:

for ( var i : int = 0; i < people.length; i++ ) ...

That's bad, because each time the loop iterates, it has to dig into people and access its length property. I get a boost in optimization (without losing clarity) by doing this:

var numPeople : int = people.length;
for ( var i : int = 0; i < numPeople; i++ ) ...

But I'm bothered by the fact that both i and numPeople are throw-away variables (just needed for loop mechanics), yet only one is declared outside the for statement. So here's the trick:

for ( var i : int = 0, numPeople = people.length; i < numPeople; i++ ) ...

I advocate either that or this:

var i : int = 0;
var numPeople : int = people.length;
for ( i; i < numPeople; i++ ) ...

Note: you could also write the for loop this way:

for ( ; i < numPeople ; i++ )...

Trick two:

Let's say you need to loop backwards through an array by index. You could do this:

var arr : Array = [ 10, 20, 30, 40, 50 ];
for ( var i : int = arr.length - 1; i <= 0; i-- )
{
trace( arr[ i ] );
}

//output: 50, 40, 30, 20, 10

or (here's the trick) you could just do this:

var arr : Array = [ 10, 20, 30, 40, 50 ];
var i : int = arr.length - 1;
while( i-- )
{
trace( arr[ i ] );
}

//output: 50, 40, 30, 20, 10

Why does that work? Won't i keep decrementing past zero (-1, -2, -3...)? No, because in the Boolean sense, zero reads as false (all other numbers read as true). So while( 0 ) will stop the loop.

One final trick:

I didn't learn this one from the article I liked to above. I've seen it in various places.

Let's say you want to either set a variable equal to a value read in from an xml file OR, if there is no value in the xml file, you want to set the variable to some default value. (Hint: note the word "or" in the previous sentence.)

Here's what I used to do:

if ( valueFromFile == null ) speed = valueFromFile;
else speed = 10;

or I might have done this:

speed = ( valueFromFile == null ) ? valueFromFile : 10;

or even this:

speed = ( valueFromFile ) ? valueFromFile : 10;

What I hate about all those versions is the stuttering of "valueFromFile." Via the trick, I can eliminate it like so:

speed = valueFromFile || 10;

I love how clean this looks, especially when you're using it with multiple values:

var speed : int = speedFromFile || 10;
var color : uint = colorFromFike || 0xFF00FF;
var name : String = nameFromFile || "George";

getters and setters: no more faux properties

I am obsessed with making my code as easy to use as possible. One way I do that is to stay consistent whenever I can. If class A's kill() method does the same thing as class B's destroy() method, they shouldn't have two different names. They should both be kill() or destroy().

Adobe is terribly inconsistent (probably due to too many developers working without tight supervision) when deciding if properties should be accessed via methods or faux properties (getters/setters). Is it length or length(). Depends: arrays have length; XMLLists have length(). That always trips me up.

Accessors can present themselves as either properties or methods. For consistency, I've decided to use only one of these. It doesn't make sense to forgo methods, since I have to use methods for other purposes. So I'm forgoing properties.

No more "public function get length()" for me. From now on, I'll use getLength() and setLength(). For Booleans, I'll use isCold() and hasChildren(). Anyone using my classes -- including me -- will no longer have to look up a member to see if it's accessed as a property or method. It will always be a method.

Of course, another clean way of working is to be very rigid about whether a member is something a class has or something a class can do. A class might HAVE length but it can't DO length. I like this distinction in theory, but I'd rather not have to think about it in practice -- especially since some cases are ambiguous: does a book flipTo() page 18 or is its currentPage page 18?

Friday, November 6, 2009

Why You Should Override Clone In Event Subclasses

When I first learned how to code custom events in Actionscript 3.0, a friend told to override clone() when I subclassed flash.events.Event, but I didn't really understand why. So I ignored his advice.

It didn't seem to matter. I never wrote my own version of clone() and yet I never ran into any problems. But my friend's advice nagged at me. So I asked him why I should override clone(). He explained that if I didn't, clone() would return the standard Event type rather than my custom event type.

Let's say I create an Event subclass called KissEvent:


public calls KissEvent extends Event
{
public var withTongue : Boolean = true;

public static const BIG_SMOOCH : String = "bigSmooch";

...
}


As usual with events, I can set up a listener for KissEvent:

this.addEventListener( KissEvent.BIG_SMOOCH, onKiss );


function onKiss( kissEvent : KissEvent ) : void
{
...
}


The clone() problem occurs if I try to copy the Event via the clone() method it inherited from flash.events.Event:


function onKiss( kissEvent : KissEvent ) : void
{
var kissEventClone = kissEvent.clone();

trace( kissEvent.withTongue );
trace( kissEventClone.widthTongue );
}


The first trace, above, will output true. The second will cause an error. Flash will tell me that Event has no such property as withTongue, and in fact it doesn't. Sure, KissEvent has such a property, but clone() doesn't spit out KissEvents; it spits out Events.

public function clone() : Event

And you can't fool it this way:

trace( ( kissEventClone as KissEvent ).widthTongue );

Flash won't allow you to cast the clone as a KissEvent, because KissEvents MUST have withTongue properties. clone() spits out Events, which don't have withTongue properties, so there's no way Flash can convert an Event to a KissEvent. My variable name, kissEventClone, is misleading, because it really just holds an Event, not a kissEvent.

Once my friend explained this to me, I understood the problem, but I had a hard time caring about it. How often do I need to clone an event object? So far in my AS-coding experience, the answer is "never." The problem seems more theoretical than nuts-and-bolts actual.

But a year later, I encountered the REAL problem: double dispatches.

Let me explain: sometimes I create systems in which a listener forwards an event object to another listener. The first listener is a sort of middle-man between the dispatcher and the second listener. The middle man is both a listened and a dispatcher. It listens to the event, and, when it receives it, it dispatches the event to a second listener.

For example, say a game character has to listen for bullets coming at him. If a bullet hits him, he stops the bullet from flying any further and dies. That's the case UNLESS the character is a ghost. If a ghost gets hit by a bullet, it passes right trough him, so he just passes the event on to anything else that might be hit by it. Ghosts, like all characters, listen to Guns. Walls listen to Ghosts, because a Ghost might dispatch a bullet that passed through it, and that bullet might lodge in a wall.


event event
gun (dispatcher) --------------> ghost (dispatcher) ------------> back wall


Trouble is, a listener can't simply pass on an event. It can only pass on a cloned copy of the event. (That's a built-in "feature" of Flash's event system).


event event-clone
gun (dispatcher) --------------> ghost (dispatcher) -------------> back wall


Let's say that BulletEvents have a custom property called speed. Since clone() outputs Events (not BulletEvents), speed will be passed from gun to ghost but not from ghost to back wall.


event (speed=3) clone
gun (dispatcher) ---------------> ghost (dispatcher) -----------> back wall


So if the back wall tries to access speed, it's not going to find anything. Finally understanding the REAL problem, I made sure to override clone() in all my custom events. Here's a toy version of the solution:


public class MyEvent extends Event
{
public var myName : String;

public static const SOMETHING_HAPPENED : String = "somethingHappened";

public function MyEvent( type : String, myName : String,
bubbles : Boolean = true,
cancelable : Boolean = false )
{
this.myName = myName;
super( type, bubbles, cancelable );
}

override public function clone() : Event
{
return new MyEvent( super.type, myName, super.bubbles, super.cancelable );
}
}


Notice the overridden clone method. It returns a new MyEvent instance containing all the properties of the current instance. It truly IS a clone!

The one unfortunate thing is that clone() can't return a MyEvent. It must return an Event. That's because the clone() method in the superclass returns Event, and when you override a superclass's method, your new version must return the same type of object. But the returned Event is created by this statement: new MyEvent( super.type, myName, super.bubbles, super.cancelable ), so it DOES contain the myName property. This means we'll be able to use casting to get at myName, as I'll show below.

Now that we have our event, I'll show you the dispatcher/listen chain I have in mind:


event( w/myName ) clone( w/myname)
MyEventDispatcher ---------------> MyEventGrabbler (dispatcher) ------------> Main


Here's the code for MyEventDispatcher:


public class MyEventDispatcher extends EventDispatcher
{
public function dispatch() : void
{
var myEvent : MyEvent = new MyEvent( MyEvent.SOMETHING_HAPPENED, "Fred" );
dispatchEvent( myEvent );
}
}


Here's the middle-man code for MyEventGrabber:


public class MyEventGrabber extends EventDispatcher
{
private var _myEventDispatcher : MyEventDispatcher;

public function MyEventGrabber()
{
_myEventDispatcher = new MyEventDispatcher();
_myEventDispatcher.addEventListener( MyEvent.SOMETHING_HAPPENED, myHandler );
}

public function startTheEventBallRolling() : void
{
_myEventDispatcher.dispatch();
}

public function myHandler( myEvent : MyEvent ) : void
{
dispatchEvent( myEvent );
}
}


You might have expected the myHandler method to look like this:


public function myHandler( myEvent : MyEvent ) : void
{
dispatchEvent( myEvent.clone() );
}


While that's perfectly legal, it's not necessary. (Though maybe it's a good idea, as it makes what's happening explicit). When you re-dispatch an event, Flash uses clone() automatically.

Finally, here's the section of the Main class that catches the clone and accesses the myName property:


var myEventGrabber : MyEventGrabber = new MyEventGrabber();
myEventGrabber.addEventListener( MyEvent.SOMETHING_HAPPENED, myHandler );
myEventGrabber.startTheEventBallRolling();

function myHandler( event : Event ) : void
{
trace( (event as MyEvent).myName ); //Fred
}


Note that I use casting here to make Flash understand that the Event is actually a MyEvent. This casting only works because I overrode the clone() method in MyEvent.

There's one more potential problem that, admittedly, is less serious than the clone() problem. If I replace the above trace with this one...

trace( event );

... I won't see the myName property listed. Instead, I'll see this:

[Event type="somethingHappened" bubbles=true cancelable=false eventPhase=2]

The simple fix is to also override the toString() property in MyEvent, since when you hand trace() an object, it uses that object's toString() method. The simplest override is this:


override public function toString() : String
{
return "myName=" + myName;
}


But that will just trace out "myName=Fred", whereas what I want is...

[Event type="somethingHappened" bubbles=true cancelable=false eventPhase=2 myName="Fred"]

So I need to append the extra info to the end of the superclass's version of to string:


override public function toString() : String
{
return super.toString + " myName=" + myName;
}


Which gives me this:

[Event type="somethingHappened" bubbles=true cancelable=false eventPhase=2] myName=Fred

Because I'm anal, I need to get the myName=Fred inside the brackets. I also need to put quotation marks around "Fred," because it's a String. That's all easy to accomplish with a tiny bit of String manipulation. Here's my final version of MyEvent, with a robust toString() method. Note that I have also made a getter for myName, which stops random processes from being able to set myName to values that didn't come from MyEventDispatcher:


public class MyEvent extends Event
{
private var _myName : String;

public static const SOMETHING_HAPPENED : String = "somethingHappened";

public function MyEvent( type : String, myName : String,
bubbles : Boolean = true,
cancelable : Boolean = false )
{
_myName = myName;
super( type, bubbles, cancelable );
}

public function get myName() : String
{
return _myName;
}

override public function clone() : Event
{
return new MyEvent( super.type, _myName, super.bubbles, super.cancelable );
}

override public function toString() : String
{
var superString = super.toString();
var newProperties : String = ' myName="' + _myName + '"]';

//removes the closing bracket symbol from the end
//of the event-property list;
superString = superString.toString().substr( 0, superString.length - 1 );

return superString + newProperties;
}

}


The extra two methods, clone() and toString() add a lot of typing to the previously quick job of creating custom events. So I recommend that you use whatever templating system your IDE supports. If you're able to paste in generalized version of those method, it only takes a few seconds to make the necessary changes to support your particular event.