Found a Use Case for flash.utils.Proxy

Really edge case here, but hey, it’s something.

Background

In creating a Vidego API (video content management API) example in Flash CS3, I ran into problems making an AS3 version from the AS2 version. Flash CS3 doesn’t haven an Accordion component, so I went about using a List instead. My problem with the List in CS3 compared to Flex is that it “expects” the data to have certain properties on it. If your data doesn’t have those properties, it throws an exception. Um… ok… :: face palm :: Yes, I know labelField/labelFunction, but those should be opt-in, especially when you’ve already set a cellRenderer.

While the data model is pretty small, say 9 ValueObjects, I’m not going to start adding a “label” and “icon” property to my VO’s just to “make them work” in a Flash CS3 DataProvider and List. This would pollute the API with data the Multicast Media doesn’t officially support, confusing users of the API… and me, the writer since they’d always be empty Strings. While it’d work just dandy in Flash CS3, developers using it in Flex would be like, “Huh…?”.

While I could extend, say, the ProgramVO (a video w/ metadata basically) and add those 2 fields (label & icon) as public variables, the VidegoFactory doesn’t spit my VO’s out, it spits ProgramVO’s out. I’d have to create a new Array of my FlashCS3ListFriendlyProgramVO’s instead. Ok, not to bad… until you get around to copying the data. A LOT of extra typing that could introduce errors that wouldn’t throw exceptions if I forgot a property in my copy method. Worse, if the ProgramVO changes, I’d have to make sure to change my FlashCS3ListFriendlyProgramVO’s copy function. While HIGHLY unlikely (most API changes are 4 months minimum), it’s still just one extra place to check for errors without any player help via exceptions.

For example, the ProgramVO has 12 properties, 5 of which are complex objects and 2 arrays. That is a lot of manual data conversion and copying. That means, higher chance for introducing errors and more to update later, and re-test.

…vs. a Proxy that merely acts like the real object.

If you ask for something not approved, you’ll get an exception. You still have to make a new Array with new Proxy objects, but at least you don’t have to do a lot of error inducing typing and you still retain runtime exceptions for mis-asked for variables. Dope!

Skip the History Lesson

__resolve Back in the Day

Back in ActionScript 2 & 1, and still in JavaScript, there is a property on all Objects called “__resolve“. If you ask for a property or method that doesn’t exist on the object instance, the runtime will make a last attempt to find the property / method by calling the __resolve function in the object instance’s scope, passing the name of the property / method asked for as a String. This allows the object to return basically anything.

The first valid use of __resolve I saw was in Flash MX. Back then, we got our first real component set from Macromedia. A lot of us started to learn about modular programming. The problem was, we still used loadMovie (aka Loader). Asynchronous programming was a new concept for a lot of us, and events didn’t exist yet. So, Branden Hall attempted to create a Proxy component that loaded the external SWF for you and stored whatever method call you made.

That way, instead of writing a bunch of code to load the SWF, wait for it to finish, and THEN call the method on it, it’d do all of this for you. He did this by basically using __resolve to store the method you were calling with the arguments. When the SWF was loaded, it’d then call the methods on the loaded SWF using the stored values. Really dope idea to shield people (like me) from the complications of asynchronous programming. In the end, it looked like this:

myProxy.setLabel ( “some text” );

flash.utils.Proxy

In ActionScript 3 there is a class called flash.utils.Proxy. It has a method called getProperty that you can override to act just like the __resolve of old for properties. In AS3, if I were to access a property, it’d look something like this:

// doing this
myObject.cow = "cheese";

// results in a call in myObject's Class like this similar to a getter
function getProperty ( name : * ) : *
{
        return this[ name ] ;
}

You can create objects that allow Proxy functionality by extending it. I did this by creating a new VO called ProgramVOProxy. If you are the Flash CS3 List, and ask for label or icon properties, it’ll give those to you. If, however, you ask for something else, it’ll look on an internal stored copy of a ProgramVO. If you mis-typed something, you’ll get a runtime exception. Little error prone typing, data integrity, and runtime exceptions for the screw-ups to help you debug. Good stuff.

You can view the class, or just check out the getProperty function extracted from it below:

flash_proxy override function getProperty(name:*):*
{
        // if you need the original program, here you go!
        if (name == "program")
        {
                return program;
        }
        
        // Rather than be a jerk, we attempt to give the List control
        // a valid label
        if (name == "label")
        {
                return program.metadatas.title;
        }
        
        // As long as you aren't asking for 'icon',
        // we'll assume you're looking for ProgramVO data
        if (name != "icon")
        {
                return program[name];
        }
        else
        {
                //... otherwise, it might be here... :: shrugs ::
                // if not, BOOM!
                return this[name];
        }
}

Yes, I have to create a new Array with new data, but at least the API remains intact, free of weird variables to make one particular component set happy. Additionally, I don’t have to worry about data integrity because it’s using the original ProgramVO. If someone DOES mis-type something, they’ll still get runtime exceptions which helps in debugging.

If this were AS2, I’d hack the List’s prototype and fix it. In AS3, prototype hacking is still looked down upon and even more so mis-understood. This is merely because there are more traditional programmers doing AS3 who get nervous by “magic”, and our tools don’t really help us in prototype hacking. I’m not going to fix the Flash CS3 List control and publish a monkey patched version along with Multicast Media’s API… that’s just straight ghetto. Flex doesn’t have this problem. It’s a faulty List control and this is my solution for example code. If someone has a better idea, they have the source and go for it; whether this is ingenious or pragmatic (by adding the label and icon public variables to the ProgramVO.as and calling it a day).

The downsides? The CellRenderer loses strict-typing. Furthermore, Proxy is slow compared to native ValueObjects. How slow? :: shrugs :: I’d argue fast enough for Flash Developers.

So, edge case, yes I know. However, it gives me a good tool to use the next time I’m forced to use an AS3 Library that I don’t have the source too, prototype hacking won’t work, and/or base classes were used instead of interfaces.