November 20, 2011

AS3 and Zeo Again

Recently got around to checking a couple of items off of my todo list that had been on there way too long. In summary:

Sometimes the simple things take the longest time.

Tags: as3 csv flex zeo

December 1, 2010

Code Coverage Comparison

Having spent some time using the new ActionScript Code Coverage Plug-in for Flash Builder, I thought I'd compare it to the existing Flexcover tool.

Below are the major reasons why I'd chose one tool over the other.

Why Flexcover is the better choice:


  • Support for continuous integration systems (generate a report from the command line in common code coverage syntaxes)

  • Partial line coverage (does every part of a boolean expression get exercised to both true and false)

Why ActionScript Code Coverage is the better choice:


  • No special compilation step (just run your project with the collector enabled)

  • Ease of use (no need to load CVM files and switch out of Eclipse to view coverage)

Personally I see using the two tools complimenting each other. I see using the ActionScript Code Coverage during my development and unit testing to get quick feedback and Flexcover as part of integration and nightly builds to track coverage over time and get more detailed coverage statistics.

Tags: as3 flex tools

November 17, 2010

litl Lab (RIA Unleashed: Boston 2010)

litl Lab by Ryan Canulla and Kathryn Rotondo

Not nearly enough hands on coding, especially since half of the session was devoted to their upcoming set-top box product but for which they didn't have a hardware demo.

Flash based SDK for developing channels. Each channel has three views: card (menu with optional slideshow), focus (mouse, keyboard support), and channel view (passive view, swipe type gestures only).

User can install multiple channel instances with different settings. Think weather widget with different zip codes all displayed at once.

Card view should have minimal animation but can reflect live data.

Focus view is the most details. Put ability to change channel options in this view and things like capturing username and passwords for remote data. Can configure a website and links that will launch in the litl chrome based browser.

Channel view should be designed for distance viewing. Think of it like a screen saver, very passive, but should be used for video and games since it provides the most screen real estate. For gestures in the view put most common in the middle (least likely, somewhat likely, most likely, somewhat likely, least likely).

Keep in mind the user can switch between the three views at any time. Be smart about what you do. Remember that data should update regularly but handle the fact that the network will come and go.

A channel can store properties in either shared properties (part of the channel, consider them public) (example same channel in marketplace with different defaults), device properties (specific to the device the channel is running on, consider them private) (example font size for webbook versus TV STB), or account properties (tied to your account, consider them protected) (example Facebook username and password).

New set-top box offering will have trackpad with slide out keyboard. Will offer gestures, accelerometers, microphone, and possibly webcam. For STB you need to worry about overscan, but the litl SDK will tell you usable dimensions when switching which view is active. Important to liquify your layout as STB dimensions will vary like crazy.

Tags: api as3 flex litl riaunleashedboston2010

November 17, 2010

Beyond IoC: Advanced Experiments with Swiz (RIA Unleashed: Boston 2010)

Beyond IoC: Advanced Experiments with Swiz by Ben Clinkinbeard

Swiz is all about custom meta-data parsing as returned from describeType(). Recent changes have exposed that meta-data processing to anyone. General switch from autowire to inject.

Swiz is all about defining a list of beans that it knows about. Swiz watches for views to be added and then manages them (i.e. set beans on the view).

In general most of what you can do with a meta-data tag you could also do with an interface, but it isn't as cool.

IProcessor (root of it all)
init() - reference to Swiz instance one is operating in
priority - determine what order processors are run in

IBeanProcessor (extensions) any object that Swiz manages
setUpBean() and tearDownBean()

SwizInterfaceProcessor: checks for common interface types (backwards compatibility)

Bean is wrapper that Swiz puts around your object. It has source property and type descriptors that handles meta-data. Support for class, property, and method meta-data.

IMetadataProcessor (parse custom metadata tags)
metadataNames() - associate with more than one metadata tag
setUpMetadataTags() - metadata tags found and the bean
tearDownMetadataTags()

PostConstruct run after all injections satisfied
MetadataTag allow additional properties like "order"

var f:Function = bean.source[metadataTag.host.name];

Bad things might happen if two register the same meta-data tag. Might be good to add a mapping report to let you know what was injected where.

Unit testing custom meta-data tags is possible.

When an event is dispatched, to check permissions or security constraints, may prevent method from running.

Growing collection of third party custom meta-data processors.

New feature is event chains and command chains. Determine flow by returning AsyncToken or AsynchronousIOOperation.

Tags: as3 flex riaunleashedboston2010 swiz

October 26, 2010

Initial Zeo Data Explorer Released

I'm pleased to announce the first release of Zeo Data Explorer. For anyone that uses a Zeo to track their sleep, I've been playing with different ways to visual my sleep data, which some of you may have heard me talk about at BarCamp Boston 5. To that end I put together a generic library for parsing the CSV file you can export from the myZeo site. Along with the generic parsing library I've started exploring different ways to visual my sleep, beyond what you can do on myZeo, in an application called the Zeo Data Display. All of the source code is available on bitbucket at Zeo Data Explorer. This includes a pure AS3 library for parsing the data and a sample Flex application for visualizing it. For those that don't have a Zeo I've included a sample of my own data to get an idea of what it tracks. As time permits I hope to add additional visualizations to the tool now that the overall framework is in place. Enjoy and let me know what you think.

Tags: as3 flex zeo

October 26, 2010

Generic AS3 CSV Parser

As part of my work on the Zeo Data Explorer I found myself in need of a generic CSV parser that could handle quoted text, escaped commas, etc. While I found a few solutions none solved the problem completely or correctly. To that end I wrote a pure AS3 implementation of RFC 4180 (Common Format and MIME Type for Comma-Separated Values (CSV) Files) specification.

It does require Flash Player 10 as I really dig Vectors. I haven't done optimization of it as the speed was good enough for my purposes. For the time being this code is bundled into the Zeo Data Explorer project, but the files can be easily found in the parser package. If you have any suggestions or bugs leave a comment below.

Tags: as3 csv

September 21, 2010

Sanitize String for Regular Expression

I recently came across a need to use a user supplied input in a regular expression. To prevent any special characters in the user's string from being treated as a regular expression control character I stumbled upon this solution. Alas I can't remember where I found it but wanted to share.

/**
* Convert a random string into a format that will make sure it doesn't
* impact a regular expression when inserted into it.
* @param string String to sanitize.
* @return Sanitized string
*/
public function sanitizeForRegExp(string:String):String
{
    if (string == null)
    {
        return null;
    }
    return string.replace(new RegExp("([{}\(\)\^{{content}}amp;.\*\?\/\+\|\[\\\\]|\]|\-)","g"), "\\$1");
}

Tags: as3 flex regexp

August 24, 2010

Optional int

I've recently run across the need to have a optional int field. That is a property on a class that is of type int but can be left unset (or null). AS3 doesn't provide the Java equivalent of the Integer class so I was curious what my options are. Below are four options that I played with. If you know of others leave a comment.

Option 1: type it as Number

public class Temp {
    public var value:Number;
}

Pro: Test if value has been set using isNaN(temp.value). No compiler warnings for assignment to another int and mathematical operations.
Con: Doesn't convey that the value is of type int. Allows user to set non integer values.

Tweak: Provide a get/set that downcasts the incoming Number to an int and possible throw ArgumentError if a non int value is passed.

Option 2: type it as *

public class Temp {
    public var value:*;
}

Pro: Test if value has been set using temp.value == null or temp.value == undefined. No compiler warnings for assignment to another int and mathematical operations.
Con: Doesn't convey that the value is of type int. Allows user to set anything.

Option 3: get/set/isSet

public class Temp {
    private var _value:Number;
    public function set value(value:int):void { _value = value; }
    public function get value():int { return _value; }
    public function isValueSet():Boolean { return !isNaN(_value); }
}

Pro: Test if value has been set using temp.isValueSet(). Clear that value is of type int.
Con: Bunch of code. Not a common AS3 paradigm

Option 4: Integer class

public class Integer {
    private var _value:int;
    public function Integer(value:int) { _value = value; }
    public function valueOf():int {return _value; }
}
public class Temp {
    public value:Integer;
}

Pro: Test if value has been set using temp.value == null. Clear that value is of type int and is optional. Safe to use in mathematical operations.
Con: No direct assignment to another int. Bigger memory footprint.

Note: The use of the valueOf() function makes the Integer class do the right thing in most contexts such as var sum:int = 12 + temp.value. You do need to use valueOf() when doing direct assignment var value:int = temp.value.valueOf();.

Conclusions

I can see each of these options working based on the situation. Out of all of them Option 1 is the most appealing from a minimal code perspective and is a typical AS3 paradigm. Wrapping the setting with a conversion of the Number to int improves correctness.

Tags: as3 flex

August 27, 2008

New Event Testing Framework in FlexUnit

Part of the new FlexUnit release is a new TestCase subclass called EventfulTestCase. It provides convenience methods for testing objects that emit events. This new class can streamline your testing code and help catch unexpected events. Below is some sample code that demonstrates this new framework.

To use the new event testing framework subclass EventfulTestCase instead of TestCase.

package com.neophi.test {
    import flexunit.framework.EventfulTestCase;

    public class EventTest extends EventfulTestCase {
        // Test code here
    }
}

In a particular test method once you have the object that you want to test for assertions against, you call a new helper function called listenForEvent(). It takes three arguments:

  • source: the object that is to be listened on for the dispatched event
  • type: the type of event that the source object might dispatch
  • expected: whether the event is expected to be dispatched or now; defaults to EVENT_EXPECTED, the other choice is EVENT_UNEXPECTED (both defined in EventfulTestCase)

After your code has exercised the source to emit events, you make a call to assertEvents() with an optional message to make sure the events happened as planned. A quick example of a positive test for an event would look like this:

public function testEventExpectedPass():void {
    var eventEmittingObject:EventDispatcher = new EventDispatcher();

    listenForEvent(eventEmittingObject, Event.COMPLETE, EVENT_EXPECTED);
    eventEmittingObject.dispatchEvent(new Event(Event.COMPLETE));

    assertEvents("Expecting complete event");
}

After the event source is setup, we notify the testing framework what event we are expecting, emit the event, and then assert that is happened. In a more typical example the dispatchEvent() call would be part of the code under test. Also you aren't limited to listening for just a single event at a time. This example is just demonstrating the test framework API. When setting up an expected event via listenForEvent() the third argument defaults to EVENT_EXPECTED.

If an expected event doesn't get dispatched, the test harness will report an error as this next test demonstrates.

public function testEventExpectedFail():void {
    var eventEmittingObject:EventDispatcher = new EventDispatcher();

    listenForEvent(eventEmittingObject, Event.COMPLETE, EVENT_EXPECTED);

    assertEvents("Expecting complete event");
}

Testing for unexpected events works the same way but the fail and pass conditions are reversed.

public function testEventUnexpectedPass():void {
    var eventEmittingObject:EventDispatcher = new EventDispatcher();

    listenForEvent(eventEmittingObject, Event.COMPLETE, EVENT_UNEXPECTED);

    assertEvents("Not expecting complete event");
}

In this case the COMPLETE event is unexpected so by not firing the event the assertion passes, which is what we want. Just to flesh out the example, if an event is unexpected but does fire the assertEvents() call will fail as in this example:

public function testEventUnexpectedFail():void {
    var eventEmittingObject:EventDispatcher = new EventDispatcher();

    listenForEvent(eventEmittingObject, Event.COMPLETE, EVENT_UNEXPECTED);
    eventEmittingObject.dispatchEvent(new Event(Event.COMPLETE));

    assertEvents("Not expecting complete event");
}

In this case because an unexpected event fired it is an error.

Besides listenForEvent() and assertEvents(), two properties are exposed for examining the events that are listened for: lastDispatchedExpectedEvent holds the last event captured by listenForEvent() and dispatchedExpectedEvents holds all of the events captured. This last example shows the ability to listen for multiple events in different states, how events not registered with the listener are ignore, and uses these two convenience properties.

public function testMultipleEventsPass():void {
    var eventEmittingObject:EventDispatcher = new EventDispatcher();

    listenForEvent(eventEmittingObject, Event.INIT, EVENT_EXPECTED);
    listenForEvent(eventEmittingObject, Event.COMPLETE, EVENT_EXPECTED);
    listenForEvent(eventEmittingObject, ErrorEvent.ERROR, EVENT_UNEXPECTED);

    eventEmittingObject.dispatchEvent(new Event(Event.INIT));
    eventEmittingObject.dispatchEvent(new Event(Event.CHANGE));
    eventEmittingObject.dispatchEvent(new Event(Event.COMPLETE));

    assertEvents("Multiple events");

    assertEquals(Event.COMPLETE, lastDispatchedExpectedEvent.type);
    assertEquals(2, dispatchedExpectedEvents.length);
}

Some closing notes:


  • The order that the events are added by listenForEvent() doesn't matter. The asserts just check that events were or were not fired.

  • The event assertion framework will work with asynchronous events. You'll just want to wait to call assertEvents() in the final handler for your test.

  • The number of times that an event is dispatched doesn't matter.

  • assertEvents() can be called multiple times.

Tags: as3 events flexunit

February 25, 2008

Puzzling Proxy Problem: Solved

The short version is what AS3 operator triggers a call to the isAttribute() method of a Proxy? The answer, none. isAttribute() is a utility function provided by Proxy that can be called to determine if the name passed to a function was specified as an attribute. A couple of Proxy's methods can't be called in an attribute context, as noted below. I've created a sample Proxy class called MyProxy to help show what's going on:

package com.neophi.test {
    import flash.utils.Proxy;
    import flash.utils.flash_proxy;

    public dynamic class MyProxy extends Proxy {
        override flash_proxy function callProperty(name:*, ... rest):* {
            trace("callProperty", name, rest);
            flash_proxy::isAttribute(name);
            return null;
        }

        override flash_proxy function deleteProperty(name:*):Boolean {
            trace("deleteProperty", name);
            flash_proxy::isAttribute(name);
            return false;
        }

        override flash_proxy function getDescendants(name:*):* {
            trace("getDescendants", name);
            flash_proxy::isAttribute(name);
            return null;
        }

        override flash_proxy function getProperty(name:*):* {
            trace("getProperty", name);
            flash_proxy::isAttribute(name);
            return null;
        }

        override flash_proxy function hasProperty(name:*):Boolean {
            trace("hasProperty", name);
            flash_proxy::isAttribute(name);
            return false;
        }

        // Don't override isAttribute(), it is a utility function
        // used by methods that specify a name:* parameter
        // to determine if the name argument was specified as an
        // attribute. It doesn't look like there is any other
        // way to determine if a name was specified as an
        // attribute besides calling Proxy's isAttribute()
        // implementation. 
        override flash_proxy function isAttribute(name:*):Boolean {
            var result:Boolean = super.flash_proxy::isAttribute(name);
            trace("isAttribute", name, result);
            return result;
        }

        override flash_proxy function nextName(index:int):String {
            trace("nextName", index);
            return null;
        }

        override flash_proxy function nextNameIndex(index:int):int {
            trace("nextNameIndex", index);
            return (1 - index);
        }

        override flash_proxy function nextValue(index:int):* {
            trace("nextValue", index);
            return null;
        }

        override flash_proxy function setProperty(name:*, value:*):void {
            trace("setProperty", name, value);
            flash_proxy::isAttribute(name);
        }
    }
}

I then exercise all of the methods (with and without namespaces) on MyProxy with this code:

private function go():void
{
    namespace myNamespace = "com.neophi.test";
    var myProxy:MyProxy = new MyProxy();

    // callProperty()
    myProxy.foo();
    // Compiler error: 1041: Attributes are not callable.
    // myProxy.@foo();
    myProxy.myNamespace::foo();
    // Compiler error: 1041: Attributes are not callable.
    // myProxy.@myNamespace::foo();

    // deleteProperty(): uses isAttribute()
    delete myProxy.foo;
    delete myProxy.@foo;
    delete myProxy.myNamespace::foo;
    delete myProxy.@myNamespace::foo;

    // getDescendents(): uses isAttribute()
    myProxy..foo;
    myProxy..@foo;
    myProxy..myNamespace::foo;
    myProxy..@myNamespace::foo;

    // getProperty(): uses isAttribute()
    myProxy.foo;
    myProxy.@foo;
    myProxy.myNamespace::foo;
    myProxy.@myNamespace::foo;

    // hasProperty()
    "foo" in myProxy;
    // Compiler error: 1084: Syntax error: expecting identifier before foo.
    // @"foo" in myProxy;
    new QName(myNamespace, "foo") in myProxy;
    // Compiler error: 1084: Syntax error: expecting identifier before new.
    // @new QName(myNamespace, "foo") in myProxy;

    // nextName(): uses nextNameIndex() 
    for (var string:String in myProxy) {
        trace(string);
    }

    // nextValue(): uses nextNameIndex() 
    for each (var object:Object in myProxy) {
        trace(object);
    }

    // setProperty(): uses isAttribute()
    myProxy.foo = "bar";
    myProxy.@foo = "bar";
    myProxy.myNamespace::foo = "bar";
    myProxy.@myNamespace::foo = "bar";
}

The output of running is below (whitespace added to match up with blocks above):

callProperty foo
isAttribute foo false
callProperty com.neophi.test::foo
isAttribute com.neophi.test::foo false

deleteProperty foo
isAttribute foo false
deleteProperty foo
isAttribute foo true
deleteProperty com.neophi.test::foo
isAttribute com.neophi.test::foo false
deleteProperty com.neophi.test::foo
isAttribute com.neophi.test::foo true

getDescendants foo
isAttribute foo false
getDescendants foo
isAttribute foo true
getDescendants com.neophi.test::foo
isAttribute com.neophi.test::foo false
getDescendants com.neophi.test::foo
isAttribute com.neophi.test::foo true

getProperty foo
isAttribute foo false
getProperty foo
isAttribute foo true
getProperty com.neophi.test::foo
isAttribute com.neophi.test::foo false
getProperty com.neophi.test::foo
isAttribute com.neophi.test::foo true

hasProperty foo
isAttribute foo false
hasProperty com.neophi.test::foo
isAttribute com.neophi.test::foo false

nextNameIndex 0
nextName 1
null
nextNameIndex 1

nextNameIndex 0
nextValue 1
null
nextNameIndex 1

setProperty foo bar
isAttribute foo false
setProperty foo bar
isAttribute foo true
setProperty com.neophi.test::foo bar
isAttribute com.neophi.test::foo false
setProperty com.neophi.test::foo bar
isAttribute com.neophi.test::foo true

That then is a complete run down of all the Proxy methods and how to use them. I'd like to thank Jacob Wright for the pointer on how isAttribute() is used.

Tags: as3 flex proxy

February 25, 2008

Abusing try..catch and throw

While looking something else up in the AS3 documentation this long weekend, I ran across this comment:

Typically, you throw instances of the Error class or its subclasses (see the Example section).

Emphasis added by me. If one typically does something, that means you can also not do it :) The throw statement takes an expression as its argument. The convention is to have it be a subclass of Error. This post isn't about that. In fact this post is a mental exercise as I don't recommend breaking from that convention, but I'm sure it might get someone's creative juices flowing, as I've not thought of a compelling use case, yet.

To demonstrate the alternative usage of throw, the code below simulates a switch statement branching based on the type of object being passed in. This code doesn't do anything with the value, but considering its all fun and games anyway extrapolating to doing some type conversion based on the incoming type should be easy. I've included all the standard primitive and top level classes, which are more examples than are needed to demonstrate the idea, but I was curious:

// This is an example of an AS3 language
// possibility, don't write code like this.
private function catchAsSwitch(value:*):void {
    try {
        throw value;
        // Tested alphabetically unless noted
        // otherwise       
    } catch(type:Array) {
        trace("Array");
    } catch(type:Boolean) {
        trace("Boolean");
    } catch(type:Class) {
        trace("Class");
    } catch(type:Date) {
        trace("Date");
        // This is the normal use case
    } catch(type:Error) {
        trace("Error");
    } catch(type:Function) {
        trace("Function");
    } catch(type:int) {
        trace("int");
        // uint must come before Number
        // since a uint satisfies both
        // is uint and is Number
    } catch(type:uint) {
        trace("uint");
    } catch(type:Namespace) {
        trace("Namespace");
    } catch(type:Number) {
        trace("Number");
    } catch(type:QName) {
        trace("QName");
    } catch(type:RegExp) {
        trace("RegExp");
    } catch(type:String) {
        trace("String");
    } catch(type:XML) {
        trace("XML");
    } catch(type:XMLList) {
        trace("XMLList");
        // Object must go last since everything
        // above satisfies is Object
    } catch(type:Object) {
        trace("Object");
        // Like switches' default
    } catch(type:*) {
        trace("*");
    }
}

An example function that calls the method with the various types:

private function go():void
{
    catchAsSwitch(new Array());
    catchAsSwitch(true);
    catchAsSwitch(Class);
    catchAsSwitch(new Date());
    catchAsSwitch(new Error());
    catchAsSwitch(function():void{});
    catchAsSwitch(-42);
    catchAsSwitch(0xFFFFFFFF);
    catchAsSwitch(new Namespace("com.neophi.test"));
    catchAsSwitch(42.42);
    catchAsSwitch(new QName("foo"));
    catchAsSwitch(/regexp/);
    catchAsSwitch("foo");
    catchAsSwitch(<foo/>);
    catchAsSwitch(<foo/>.children());
    catchAsSwitch(new Button());
    catchAsSwitch(null);
    catchAsSwitch(undefined);
}

The output of running that function is:

Array
Boolean
Class
Date
Error
Function
int
uint
Namespace
Number
QName
RegExp
String
XML
XMLList
Object
*
*

As noted in the comments of catchAsSwitch() catch clauses are evaluated in order so in some cases if the value could satisfy multiple different types the more specific is listed first. This is something to keep in mind when using the typical case, in that Error should be listed after more specific subclasses like ArgumentError.

Now that this alternative syntax exists could we do something with it? Well as I mentioned above I've not thought of a compelling case yet. In fact this entire post is the result of a big tangent on my part. It started off with reading some of Francis Cheng's recent posts about Proper Tail Calls (PTC). Having taken a compiler course from William Clinger in the past in which I had to implement PTC I found the topic interesting.

Reading those posts led me to the EMCAScript site and looking over the ES4 documentation. In one document comments about scoping issues with catch blocks had me discover that throw took an expression. Which made me remember some discussion about using throw instead of return for functions when people were first exploring Java. The net result of that discussion was a comparison to the considered harmful idea since it obfuscated the code's intent. I can't find a reference to the discussion but Cheng's PTC example prompted me to write a throw equivalent. It still suffers from stack overflow but again maybe it will spark someone else's imagination for a way to use the technique.

private function factorial(x:int):int {
    try {
        calculateFactorial(x, 1);
    } catch(result:int) {
        return result;
    }
    return 1;
}

private function calculateFactorial(x:int, result:int):void {
    if (x < 1) {
        throw result;
    }
    calculateFactorial(x - 1, result * x);
}

I don't know enough about the internals of the AVM to know if popping up the stack looking for a catch block is better than just returning the value in the current AVM. Obviously if PTC is added to ES4 and the AVM picks it up any such approach like the one above will be vastly slower. The nice mental exercise is that you have a function "returning" a value without returning a value.

In the process of experimenting with alternative try..catch use cases I ran into some compiler issues. Being a nonstandard use case I'm not surprised they didn't work. Yet another reason to not try this at home.

Update: Shortly after posting this I found a post that talks about using try..catch as an alternative flow control mechanism. This captures most of the same thoughts as that old Java thread I mentioned above.

Tags: as3 catch throw try

November 30, 2007

Styles, Fonts, and Compile Time

There has been some recent conversation about the impact of styles and fonts on compilation time in Flex Builder 3. I figured I'd take the project I'm currently working on and see what the numbers came out as.

Some more details about the test: About 700KB of raw .as and .mxml code. 2 separate CSS files are imported. 120KB of TTF fonts. 650KB of SWF fonts. Compiling using Flex 2.0.1 Hotfix 3 SDK. Each tests was run 3 times with the average time reported. Each test was run by changing text in the top level MXML component, saving it, and timing a manual build. Timing was from time of click until the progress view reported the build was finished. Copy non-embedded and generate HTML template were disabled.

As with all measurements these should be taken with a grain of salt and are meant to be representative. Your project will vary, yadda, yadda, yadda.

Compile State Compile Time (in seconds)
All styles, 11 SWF fonts, and 2 TTF fonts 11.3
No styles or fonts 4.8
All styles and no fonts 6.9
All styles and 8 SWF fonts 9.1
All styles and 2 TTF fonts 9.1
All styles and 3 SWF fonts 8.1

Clearly using TTF encoded fonts has a higher overhead than SWF encoded fonts. More fonts take more time. The next item to explore is using Flex Builder 3's compile CSS to SWF option. Doing that would require looking at application startup time since the styles would no longer be compiled in but instead loaded during startup.

Tags: as3 css flex

October 24, 2007

MAX 2007: Best Practices for Developing with ActionScript 3.0

Rough Draft Notes

David Hassoun

Talk will focus on resources and guides, this isn't a how to.

Three main pieces: Analysis (what to do), Design (how to do it), and Implementation (creating code)

Saffron AIR UML Tool, Enterprise Architect, UML and a focus on class diagrams
Unit testing frameworks include FlexUnit and ASUnit

Coding Guidelines: Doesn't matter what you pick, but consistency is key.
Areas to consider: object creation policy, variables typing and scoping, package structure, class structure, naming conventions, code commenting, and curly braces

Not confirmed but mentioned something about declaring multiple variables on a single line as being more efficient. (ala. private var foo:String = "", bar:String = "";)

Program to interfaces.

Memory and performance. Areas to consider include: deferred instantiation, paging in data, don't load assets until needed, remove references, remove trace statements, use the mxmlc optimize flag (on by default I believe), use int as type of loop counter.
Unconfirmed but mentioned accessing static member variable in a loop is more expensive then copy value to local variable and referencing that instead.

Architecture: Create and use frameworks (reusable code blocks).: provide proven and targeted solutions and the expense of code size and potential bugs. Design patterns are repeatable solutions and should be used as needed. RSLs and modules great for sharing code and leveraging testing effort (once tested can be used again with higher confidence). Look at using -link-report and -load-externs command line options. Flex 3 is adding cached framework library. Flex Builder 3 has UI for setting up and using modules.

Best practices: code management and version control. Create code integrity, do unit testing, and continuous integration.

Tags: as3 flex max2007chicago

March 11, 2007

Asynchronous Testing with FlexUnit

When testing components that have asynchronous behavior you need to use FlexUnit's addAsync() method in order to correctly handle the events that fire. The reason for this is that unless you tell FlexUnit that you are expecting an asynchronous event, once your test method finishes FlexUnit will assume that the test is done and there were no errors. This can lead to false positives and annoying popup error dialogs with an assert fails. Below are some examples of how to use addAsync().

I'll start off with what not to do so you can get an idea of why you need addAsync(). Let's write a simple test that verifies that the flash.utils.Timer class fires events the way we think it should. The first attempt might look like this:

package com.example {
    import flexunit.framework.TestCase;
    import flash.utils.Timer;
    import flash.events.TimerEvent;

    public class TimerTest extends TestCase {
        private var _timerCount:int;

        override public function setUp():void {
            _timerCount = 0;
        }

        public function testTimer():void {
            var timer:Timer = new Timer(3000, 1);
            timer.addEventListener(TimerEvent.TIMER, incrementCount);
            // the next line should not be written like this, it can produce false positives
            timer.addEventListener(TimerEvent.TIMER_COMPLETE, verifyCount);
            timer.start();
        }

        private function incrementCount(timerEvent:TimerEvent):void {
            _timerCount++;
        }

        private function verifyCount(timerEvent:TimerEvent):void {
            assertEquals(1, _timerCount);
        }
    }
}

Nothing fancy here, we declare a single test method, create the Timer, and then start it. It should run once and then stop. If you add this test to your test suite and run it, you get a nice green bar. This is a false positive! The assertEquals() in the verifyCount() method didn't really contribute to the test passing. Try changing it to:

assertEquals(2, _timerCount);

When you rerun the test you'll get another green bar. Then a few seconds later an error dialog box pops up with the following message:

Error: expected:<2> but was:<1> at flexunit.framework::Assert$/flexunit.framework:Assert::failWithUserMessage()[C:\Documents and Settings\mchamber\My Documents\src\flashplatform\projects\flexunit\trunk\src\actionscript3\flexunit\framework\Assert.as:209] at flexunit.framework::Assert$/flexunit.framework:Assert::failNotEquals()[C:\Documents and Settings\mchamber\My Documents\src\flashplatform\projects\flexunit\trunk\src\actionscript3\flexunit\framework\Assert.as:62] at flexunit.framework::Assert$/assertEquals()[C:\Documents and Settings\mchamber\My Documents\src\flashplatform\projects\flexunit\trunk\src\actionscript3\flexunit\framework\Assert.as:54] at com.example::TimerTest/com.example:TimerTest::verifyCount()[C:\Work\Eclipse3.2\Fresh\AsyncTest\src\com\example\TimerTest.as:26] at flash.events::EventDispatcher/flash.events:EventDispatcher::dispatchEventFunction() at flash.events::EventDispatcher/dispatchEvent() at flash.utils::Timer/flash.utils:Timer::tick()

But, but, the test bar was green! FlexUnit didn't know you where waiting for an event, as a result when the testTimer() method finished, that test was clean. The error dialog pops up because FlexUnit isn't around to catch the error and turn it into a pretty message. This also shows that even though the test finished our object was still running in the background. We can fix this first issue by adding a tearDown() method and use addAsync() to wrap the function that should be called along with specifying the maximum time to wait for that function to be called. The function returned by addAsync() is used in place of your original function. In the example above, the second listener function passed into the addEventListener() call is where addAsync() will come into play. The changes to TimerTest look like this:

private var _timer:Timer;

override public function tearDown():void {
    _timer.stop();
    _timer = null;
}

public function testTimer():void {
    _timer = new Timer(3000, 1);
    _timer.addEventListener(TimerEvent.TIMER, incrementCount);
    _timer.addEventListener(TimerEvent.TIMER_COMPLETE, addAsync(verifyCount, 3500));
    _timer.start();
}

I've taken the original function and wrapped it in an addAsync() and added the maximum time that the function can take to be called. Since my Timer is set to run in 3000ms I gave myself a little buffer. With this change and the assert testing for a count of 2, I'll get a red bar when the test runs. Additionally I added a tearDown() method so that regardless of what happens in the test the Timer will stop running. When doing asynchronous testing it is important to clean up like this otherwise you can get objects hanging round in memory doing things you don't want. On that note I'd also recommend that the event listeners added to the timer use weak references. That way in the tearDown() function nulls out the Timer that object can be garbage collected. The update code would look like this:

_timer.addEventListener(TimerEvent.TIMER, incrementCount, false, 0, true);
_timer.addEventListener(TimerEvent.TIMER_COMPLETE, addAsync(verifyCount, 1500), false, 0, true);

Now that we added in that timeout to the verifyCount() call, you'll also get a red bar if the function isn't called in the timeout specified. Drop the timeout to 1500ms and rerun the test. You should now get the following error:

Error: Asynchronous function did not fire after 1500 ms at flexunit.framework::Assert$/fail()[C:\Documents and Settings\mchamber\My Documents\src\flashplatform\projects\flexunit\trunk\src\actionscript3\flexunit\framework\Assert.as:199] at flexunit.framework::AsyncTestHelper/runNext()[C:\Documents and Settings\mchamber\My Documents\src\flashplatform\projects\flexunit\trunk\src\actionscript3\flexunit\framework\AsyncTestHelper.as:96] at flexunit.framework::TestCase/flexunit.framework:TestCase::runTestOrAsync()[C:\Documents and Settings\mchamber\My Documents\src\flashplatform\projects\flexunit\trunk\src\actionscript3\flexunit\framework\TestCase.as:271] at flexunit.framework::TestCase/runMiddle()[C:\Documents and Settings\mchamber\My Documents\src\flashplatform\projects\flexunit\trunk\src\actionscript3\flexunit\framework\TestCase.as:192] at flexunit.framework::ProtectedMiddleTestCase/protect()[C:\Documents and Settings\mchamber\My Documents\src\flashplatform\projects\flexunit\trunk\src\actionscript3\flexunit\framework\ProtectedMiddleTestCase.as:54] at flexunit.framework::TestResult/flexunit.framework:TestResult::doProtected()[C:\Documents and Settings\mchamber\My Documents\src\flashplatform\projects\flexunit\trunk\src\actionscript3\flexunit\framework\TestResult.as:237] at flexunit.framework::TestResult/flexunit.framework:TestResult::doContinue()[C:\Documents and Settings\mchamber\My Documents\src\flashplatform\projects\flexunit\trunk\src\actionscript3\flexunit\framework\TestResult.as:109] at flexunit.framework::TestResult/continueRun()[C:\Documents and Settings\mchamber\My Documents\src\flashplatform\projects\flexunit\trunk\src\actionscript3\flexunit\framework\TestResult.as:79] at flexunit.framework::AsyncTestHelper/timerHandler()[C:\Documents and Settings\mchamber\My Documents\src\flashplatform\projects\flexunit\trunk\src\actionscript3\flexunit\framework\AsyncTestHelper.as:121] at flash.utils::Timer/flash.utils:Timer::_timerDispatch() at flash.utils::Timer/flash.utils:Timer::tick()

That's the quick introduction to addAsync(). Now onto some of the additional features of addAsync() that can be helpful. Say we wanted to test that a Timer is correctly called twice within a specified period of time. The incrementCount() function can easily be reused but the verifyCount() method has a hard coded assertEquals() in it. The optional 3rd argument to addAsync() is an argument called passThroughData, which can be anything. In this case I'm going to pass what I expect the count to be when the Timer finishes allowing me to reuse the same verify function. With these changes the functions now looks like this:

public function testTimer():void {
    _timer = new Timer(1000, 1);
    _timer.addEventListener(TimerEvent.TIMER, incrementCount, false, 0, true);
    _timer.addEventListener(TimerEvent.TIMER_COMPLETE, addAsync(verifyCount, 1500, 1), false, 0, true);
    _timer.start();
}

public function testTimer2():void {
    _timer = new Timer(500, 2);
    _timer.addEventListener(TimerEvent.TIMER, incrementCount, false, 0, true);
    _timer.addEventListener(TimerEvent.TIMER_COMPLETE, addAsync(verifyCount, 1500, 2), false, 0, true);
    _timer.start();
}

private function verifyCount(timerEvent:TimerEvent, expectedCount:int):void {
    assertEquals(expectedCount, _timerCount);
}

In both cases I'm passing along the expected count and have created a generic verify method. The object that you pass can be anything which makes it a very powerful way to write generic asynchronous event verifiers. But wait there's more!

The last optional argument to addAsync() is a way to verify that the event didn't happen. Instead of getting a red bar and the "Error: Asynchronous function did not fire after 1500 ms", you can verify that based on the event not firing, everything is as it should be. For example I could verify that after 1500ms a 1000ms Timer only fired one event and the complete event never fired. This last version of the test class does that. I also modified things a little since if you include passThroughData, it gets passed to both the regular function and the failFunction. This isn't a bad thing as it provides a way to write a generic failFunction handler like the way the generic verify handler was written. Note that the failFunction handler doesn't need to worry about getting an event passed in like the normal listener function since the event didn't fire.

package com.example {
    import flexunit.framework.TestCase;
    import flash.utils.Timer;
    import flash.events.TimerEvent;

    public class TimerTest extends TestCase {
        private var _timerCount:int;
        private var _timer:Timer;

        override public function setUp():void {
            _timerCount = 0;
        }

        override public function tearDown():void {
            // cleanup to make sure the Timer doesn't keep running
            _timer.stop();
            _timer = null;
        }

        public function testTimer():void {
            runTimer(1000, 1, 1500, 1);
        }

        public function testTimer2():void {
            runTimer(500, 2, 1500, 2);
        }

        public function testNotDone():void {
            runTimer(1000, 2, 1500, -1, 1);
        }

        private function runTimer(delay:int, count:int, timeout:int, goodCount:int, badCount:int = -1):void {
            _timer = new Timer(delay, count);
            // use weak references to make sure the Timer gets GC when we are done
            _timer.addEventListener(TimerEvent.TIMER, incrementCount, false, 0, true);
            // pass both a good an bad handler along with counts so the verify methods
            // can detect what happened
            _timer.addEventListener(TimerEvent.TIMER_COMPLETE, addAsync(verifyGoodCount, timeout, {goodCount: goodCount, badCount: badCount}, verifyBadCount), false, 0, true);
            _timer.start();
        }

        private function incrementCount(timerEvent:TimerEvent):void {
            _timerCount++;
        }

        private function verifyGoodCount(timerEvent:TimerEvent, extraData:Object):void {
            if (extraData.goodCount == -1)
            {
                fail("Should have failed");
            }
            assertEquals(extraData.goodCount, _timerCount);
        }

        private function verifyBadCount(extraData:Object):void {
            if (extraData.badCount == -1)
            {
                fail("Should not have failed");
            }
            assertEquals(extraData.badCount, _timerCount);
        }
    }
}

Feel free to play with this final version to test how different asynchronous scenarios are handled in FlexUnit.

Some additional notes:
Make sure the listener function name doesn't start with test, otherwise FlexUnit will think that it is a test method and try to run it.

I've noticed some odd behavior with multiple addAsync()s set at the same time. In general you only want to have one outstanding addAsync() at a time.

If you specify passThroughData and a failFunction, the passThroughData will get passed to both the function and the failFunction.

Make sure that you cleanup any objects that could still fire events in your tearDown() method and either remove event listeners or make them weak. There is more to this topic but I'll cover that in another post.

Tags: as3 flex flexunit testing

January 25, 2007

Could not resolve * to a component implementation.

Often when refactoring code I'll extract ActionScript code out of an MXML file into an ActionScript based superclass to get a cleaner separation between logic and the view. In doing so I sometimes forget to update MXML variable declrations, leading to the confusing error:

Could not resolve <mx:states> to a component implementation.

In this case my MXML class extends another custom class and looks like:

<?xml version="1.0" encoding="utf-8"?>
<example:CustomCanvas xmlns:example="com.example.*" xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:states>
<mx:State name="default"/>
<mx:State name="custom"/>
</mx:states>
</example:CustomCanvas>

The issue is that the "mx" namespace doesn't match the root component's namespace so the MXML compiler gets confused about it being a property versus a child component. The simple fix is to just change the namespace on the property to match the root component's namespace like this:

<?xml version="1.0" encoding="utf-8"?>
<example:CustomCanvas xmlns:example="com.example.*" xmlns:mx="http://www.adobe.com/2006/mxml">
<example:states>
<mx:State name="default"/>
<mx:State name="custom"/>
</example:states>
</example:CustomCanvas>

Tags: as3 error flex2

December 31, 2006

AS3 Casting Issues

In most object oriented languages you can cast an object to something more specific in order to be able to call methods particular to the type it was cast as. This frequently comes up when you have a rich class hierarchy and for some reason can't use polymorphism to separate out behavior or more commonly have a factory like method that needs to take in a bunch of different object types but always return the same type. Since AS3 doesn't support method overloading you can't easily separate out the different object types into specialized methods and instead end up with a big if then else block.

My issue with AS3 comes in with the fact that in such as if then else block you can't easily cast primitive objects without getting some funky behavior or without needing to wrap your cast in order to detect errors. I'm sure that there are some techniques out there to avoid this issue entirely, but having now seen it come up more than once I figured I'd jot down my observations on the issue.

AS3 defines a number of top-level or global functions that mirror primitive AS3 objects types. These include String(), Array(), and Date() (currently undocumented) among others. Because these top-level functions exist, they take precedence over a cast. Consider this method.

public function asString(random:Object):String {
    return String(random);
}

public function asCustom(random:Object):Custom {
    return Custom(random);
}

While the two methods look like they would do the same thing, asString is actually calling a function, while asCustom is doing a cast. AS3 provides the as operator as a way to get around this behavior. The problem is that as won't throw casting errors, instead it just silently returns null. Maybe that's fine for what you need, but it just rubs me the wrong way.

I don't want to always have to check for null because in some cases I know that shouldn't be the case, but I also don't want null introduced because of a bug in the calling code. In my mind tracking down a bug from a class cast error is very different then trying to track down a null pointer error especially since the null could percolate further along in the code compared to the class cast error which would happen at the exact spot the cast was attempted.

The other annoying thing about the difference between cast and as is the trick it can play on you in the debugger especially if you are casting something to a String.

public function testCast():void {
    var a:String;
    a = String(null);
    trace(a);
    trace(a is String);
    a = null as String;
    trace(a);
    trace(a is String);
}
// Output:
// null
// true
// null
// false

In both cases the trace of the variable prints out null, but in the first case it is the actual string null, while in the second it is a null value. As I said before my main issue with as is that it doesn't behave like a true cast.

public function testCastError():void {
    var a:Object = new Object();
    var b:String;
    b = String(a);
    trace(b);
    trace(b is String);
    b = a as String;
    trace(b);
    trace(b is String);
    var c:UIComponent;
    c = UIComponent(a);
}
// Output:
// [object Object]
// true
// null
// false
// TypeError: Error #1034: Type Coercion failed: cannot convert Object@ef409c1 to mx.core.UIComponent.

In all three cases above the Object can't be successfully cast to the target type String and UIComponent. In the first case String() doesn't do a cast, instead we get a string representation of the object. In the second case since the types aren't compatibly as silently returns null. In the third we get what I consider the correct behavior which is a class cast error. Since as has this silent behavior you need to check for null both before and after if you want to distinguish between a null value and an incompatible cast.

In general avoid situations where you need to cast primitive objects or cast things at all, but if you do know that casting isn't always casting in AS3.

Tags: as3 casting flex

December 31, 2006

Is Operator and Type Safe Lists

In some recent coding I was playing with a custom type system and needed to add some type checking to it. What this means is that at some point I need to verify that some object is really the type I think it should be. Normally when you are coding in AS3 and need to check a type you do something like:

public function testType(object:Object):void {
    if (object is String) {
        trace("It is a String");
    } else if (object is Array) {
        trace("It is an Array");
    } else {
        trace("Its type is ?");
    }
}

testType(new String());
testType(new Array());
testType(new Object());
// Output:
// It is a String
// It is an Array
// Its type is ?

Nothing out of the ordinary there. The important thing to examine though is that the right hand side of the is operator is really an expression. Typically you just type in the class you are testing against, since you are likely to cast it on the next line, but why not try something else like:

public function returnClass(type:String):Class {
    if (type == "String") {
        return String;
    }
    if (type == "Array") {
        return Array;
    }
    throw TypeError("Unknown type " + type);
}
public function testType2(object:Object):void {
    if (object is returnClass("String")) {
        trace("It is a String");
    } else if (object is returnClass("Array")) {
        trace("It is an Array");
    } else {
        trace("Its type is ?");
    }
}

testType2(new String());
testType2(new Array());
testType2(new Object());
// Output:
// It is a String
// It is an Array
// Its type is ?

Why would you want to do such a thing? ActionScript 3 doesn't have support for generics, but by using this expression based format of the is operator you can simulate them. You don't get compile time type checking but runtime checking is better than nothing. Let's consider an application where you want to have type safe lists (you can only add items of a certain type to the list). Instead of having to create a separate list wrapper for every type you might need to support, create a standard type safe list class that knows what type each item should be. There are many different approaches to creating such a class, one possibility that uses composition is this:

package com.example {
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.utils.getQualifiedClassName;

    import mx.collections.ArrayCollection;
    import mx.collections.IList;
    import mx.events.CollectionEvent;

    // Please note this code is illustrative and has not been fully tested!
    public class TypeSafeList implements IList {
        private var _itemType:Class;
        private var _arrayCollection:ArrayCollection;
        private var _eventDispatcher:EventDispatcher;

        public function TypeSafeList(itemType:Class) {
            _itemType = itemType;
            _arrayCollection = new ArrayCollection(new Array());
            _eventDispatcher = new EventDispatcher(this);
            _arrayCollection.addEventListener(CollectionEvent.COLLECTION_CHANGE, relayEvent);
        }

        private function relayEvent(event:Event):void {
            dispatchEvent(event);
        }

        private function checkItemType(object:Object):void {
            if ((object != null) && !(object is _itemType)) {
                throw new TypeError("Item is not correct type. Wanted " + _itemType + " got " + getQualifiedClassName(object) + ".");
            }
        }

        public function addItemAt(item:Object, index:int):void {
            checkItemType(item);
            _arrayCollection.addItemAt(item, index);
        }

        public function get length():int {
            return _arrayCollection.length;
        }

        public function toArray():Array {
            return _arrayCollection.toArray();
        }

        public function getItemAt(index:int, prefetch:int = 0.0):Object {
            return _arrayCollection.getItemAt(index, prefetch);
        }

        public function itemUpdated(item:Object, property:Object = null, oldValue:Object = null, newValue:Object = null):void {
            _arrayCollection.itemUpdated(item, property, oldValue, newValue);
        }

        public function removeAll():void {
            _arrayCollection.removeAll();
        }

        public function getItemIndex(item:Object):int {
            return _arrayCollection.getItemIndex(item);
        }

        public function setItemAt(item:Object, index:int):Object {
            checkItemType(item);
            return _arrayCollection.setItemAt(item, index);
        }

        public function removeItemAt(index:int):Object {
            return _arrayCollection.removeItemAt(index);
        }

        public function addItem(item:Object):void {
            checkItemType(item);
            _arrayCollection.addItem(item);
        }

        public function hasEventListener(type:String):Boolean {
            return _eventDispatcher.hasEventListener(type);
        }

        public function willTrigger(type:String):Boolean {
            return _eventDispatcher.willTrigger(type);
        }

        public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0.0, useWeakReference:Boolean = false):void {
            return _eventDispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
        }

        public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void {
            return _eventDispatcher.removeEventListener(type, listener, useCapture);
        }

        public function dispatchEvent(event:Event):Boolean {
            return _eventDispatcher.dispatchEvent(event);
        }
    }
}

Notice how the addItemAt, setItemAt, and addItem methods call checkItemType before passing the call onto the ArrayCollection which is doing all the dirty work. By checking every place that a user can add new information to the IList we can insure that only objects matching the desired type are added. You may wonder why I'm choosing to implement IList instead of just extending ArrayCollection. In this case I don't want the extra baggage that extending ArrayCollection would bring along (support for ICollectionView and the Proxy access methods). If you did want to extend ArrayCollection you would only need to override methods that add data to the object and not create pass through methods for the other interface methods.

Now with this new TypeSafeList what does using it look like? Just like any other IList object, but with the added benefit of runtime type checking. This is some sample code that creates a TypeSafeList that can only have String items added to it:

var list:IList = new TypeSafeList(String);
trace(list.length);
var text:String = "An Item";
list.addItem(text);
trace(list.getItemAt(0));
list.addItemAt("Before An Item", 0);
trace(list.getItemIndex(text));
try {
    list.addItem(12);
} catch (typeError:TypeError) {
    trace(typeError);
}
try {
    list.addItem(new Array());
} catch (typeError:TypeError) {
    trace(typeError);
}

// Output:
// 0
// An Item
// 1
// TypeError: Item is not correct type. Wanted [class String] got int.
// TypeError: Item is not correct type. Wanted [class String] got Array.

The nice thing with the is operator is that you can also check against interfaces. Consider wanting to create a TypeSafeList that can only contain IUIComponent objects. Not only could this list contain classes that subclass UIComponent but also custom classes that implement the IUIComponent interface (not that you would really want to do such a thing). Some sample code that uses an interface with the TypeSafeList class:

var list:IList = new TypeSafeList(IUIComponent);
list.addItem(new Button());
trace(list.length);
list.addItem(new Canvas());
trace(list.length);
try {
    list.addItem("I'm not valid");
} catch (typeError:TypeError) {
    trace(typeError);
}

// Output:
// 1
// 2
// TypeError: Item is not correct type. Wanted [class IUIComponent] got String.

This entry became a little more than what I had originally planned to write about. I originally planned to stop at explaining the use of an expression for the right hand side of the is operator, but somehow ended up with this TypeSafeList class. I hope that you can see the benefit of the simple is operator and maybe someone will find that sample TypeSafeList class useful, please test it first though.

Tags: as3 flex list type

December 31, 2006

Removing Anonymous Event Listeners

One of the features that I really like about AS3 is its support of closures. There are many instances when you want to do something to an argument but don't really need or want a full blown class to encapsulate the logic. Lately I've been trying to apply this approach to event listeners and in general it just works. My problem can up when I wanted to have the event listener run only once or stop listening after some point in time. Since the removeEventListener method requires a reference to the listener that you want to remove and the listener in this case is a closure I need a way to get a reference to it. Thankfully closures provide a way to do that but it requires introducing another variable into the mix. Thankfully ActionScript provides another way to get access to the same information arguments.callee.

Arguments is a variable available in every function that is automatically supplied by the system. It is the older style of getting access to the arguments of a function that takes in an arbitrary number. In this case though the callee also gives you access to yourself. In the case of an anonymous event listener, this is all that is needed to remove it as an event listener. Now for the example:


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="handleCreationComplete();">
    <mx:Script>
        <![CDATA[
            private function handleCreationComplete():void {
                sampleButton.addEventListener(MouseEvent.CLICK, createClickListener(1));
                sampleButton.addEventListener(MouseEvent.CLICK, createClickListener(2));
            }

            private function createClickListener(clickLimit:int):Function {
                var clickCount:int = 0;
                return function(mouseEvent:MouseEvent):void {
                    clickCount++;
                    trace("Click limit", clickLimit, "registering click", clickCount);
                    if (clickCount >= clickLimit) {
                        trace("Click limit", clickLimit, "no longer listening");
                        mouseEvent.target.removeEventListener(MouseEvent.CLICK, arguments.callee);
                    }
                }
            }
        ]]>
    </mx:Script>
    <mx:Button id="sampleButton" label="Go"/>
</mx:Application>

That gives this output:

Click limit 1 registering click 1
Click limit 1 no longer listening
Click limit 2 registering click 1
Click limit 2 registering click 2
Click limit 2 no longer listening

In this example I'm programmatically adding two anonymous event listeners to my button class. They are anonymous in the fact that the function being executed isn't named. Unlike the creationComplete listener that is attached to the Application, you can only pass around the reference to the function, instead of naming it directly. As I mentioned above, since I want to remove the event listener I can't name it directly. Also since I'm creating multiple instances of it, I can't easily pass the reference to the function around. By instead using arguments.calee I avoid the need to name the function and the need to pass the function reference around.

I'll admit that this is not the most compelling example usage of this technique, but I'm sure you can extrapolate from this.

Tags: as3 event flex

December 31, 2006

Static Initializers in AS3

I couldn't find much official documentation (if you have links please pass them along) about static initializers in ActionScript 3 so I thought I'd put together a little quick reference. A static initializer is run once when a class is first loaded by the AVM. The typical user of such a block is the compiler, which uses it to assign values to static variables of the class. You also can use it to do more complex static object initialization. The example that I needed it for was to create a lookup object based on constants defined in the class. Consider a class that defines some handy constants:

package com.example {
    public class MIME {
        public static const GIF_MIME_TYPE:String = "image/gif";
        public static const JPG_MIME_TYPE:String = "image/jpeg";
        public static const PNG_MIME_TYPE:String = "image/png";
        public static const SWF_MIME_TYPE:String = "application/x-shockwave-flash";
    }
}

If you wanted to create a lookup table to quickly check if a random string matched one of these you can't use the standard object literal initialization syntax. Consider if this code is added to the MIME class:

// Don't use this, it doesn't do what you think, see below
private static const IMAGE_TYPES:Object = {GIF_MIME_TYPE:true,
    JPG_MIME_TYPE:true,
    PNG_MIME_TYPE:true,
    SWF_MIME_TYPE:true};

public static function isImage(mimeType:String):Boolean {
    return (IMAGE_TYPES[mimeType] == true);
}

If you run this test code, you don't get what you want:

trace(MIME.isImage(MIME.GIF_MIME_TYPE));
// Output: false

False? What's going on is that the text before the : in the object literal is treated as a literal string, not as a variable. What ended up happening was the literal string "GIF_MIME_TYPE" was stored in the associative array. This can be demonstrated by this little test:

trace(MIME.isImage("GIF_MIME_TYPE"));
// Output: true

Obviously not what I wanted. This is where the static initializer comes in. I only want to have to setup the lookup table once and avoid having to track if it is setup, so I put the initialization code in a block at the class level.

package com.example {
    public class MIME {
        private static const IMAGE_TYPES:Object = new Object();
        // This block is run once when the class is first accessed
        {
            IMAGE_TYPES[GIF_MIME_TYPE] = true;
            IMAGE_TYPES[JPG_MIME_TYPE] = true;
            IMAGE_TYPES[PNG_MIME_TYPE] = true;
            IMAGE_TYPES[SWF_MIME_TYPE] = true;
        }
    }
}

Yes those lines are just hanging out in the class itself and not within some method. Truth be told the {} are optional. I like to put them in a block to offset the code and make it more readable. With this updated version of IMAGE_TYPES our two tests from above now do the right thing:

trace(MIME.isImage(MIME.GIF_MIME_TYPE));
// Output: true
trace(MIME.isImage("GIF_MIME_TYPE"));
// Output: false

I should point out that the use of const in the static variable declaration is also a preference thing. Even though the IMAGE_TYPES lookup table is defined as a static constant, the contents of the object can still change at runtime. The only thing that's can't change is the object reference that IMAGE_TYPES points at. For example the following code is invalid:

package com.example {
    public class BAD {
        private static const IMAGE_TYPES:Object = new Object();
        {
            // This is a compile time error
            IMAGE_TYPES = new Object();
        }
    }
}

Trying to compile that will give you the error:

1049: Illegal assignment to a variable specified as constant.

The completed MIME class now looks like this:

package com.example {
    public class MIME {
        public static const GIF_MIME_TYPE:String = "image/gif";
        public static const JPG_MIME_TYPE:String = "image/jpeg";
        public static const PNG_MIME_TYPE:String = "image/png";
        public static const SWF_MIME_TYPE:String = "application/x-shockwave-flash";

        private static const IMAGE_TYPES:Object = new Object()
        // This block is run once when the class is first accessed
        {
            IMAGE_TYPES[GIF_MIME_TYPE] = true;
            IMAGE_TYPES[JPG_MIME_TYPE] = true;
            IMAGE_TYPES[PNG_MIME_TYPE] = true;
            IMAGE_TYPES[SWF_MIME_TYPE] = true;
        }

        public static function isImage(mimeType:String):Boolean {
            return (IMAGE_TYPES[mimeType] == true);
        }
    }
}

I get a handy lookup table populated by constants instead of strings, my test function is short and simple instead of some long if then block, and I don't need to worry about checking each time if my lookup table has been initialized. I'm happy.

Tags: as3 flex initializer static

October 21, 2006

Singleton Pattern in AS3

AS3 does not support private or protected constructors which makes it harder to implement the singleton pattern. Below are some approaches I've run across on the Internet, problems with them, and what I hope (please tell me if I'm wrong) corrections to get a real singleton pattern working.

First up is an entry by Andrew Trice about Singletons in AS3. His code was:

// faulty example
package {
    public class Singleton {
        private static var singleton : Singleton;
		
        public static function getInstance() : Singleton {
            if ( singleton == null )
                singleton = new Singleton( arguments.callee );
            return singleton;
        }
	
        //NOTE: AS3 does not allow for private or protected constructors
        public function Singleton( caller : Function = null ) {	
            if( caller != Singleton.getInstance )
                throw new Error ("Singleton is a singleton class, use getInstance() instead");
            if ( Singleton.singleton != null )
                throw new Error( "Only one Singleton instance should be instantiated" );	
            //put instantiation code here
        }
    }
}

You can defeat this approach with:

var a:Singleton = new Singleton(Singleton.getInstance);
var b:Singleton = new Singleton(Singleton.getInstance);
// a !== b

The constructor is doing a function reference comparison, but the function being compared to is available to the caller which is why it can be passed in to defeat the test.

I was also pointed at an approach created by Matt Chotin and posted to Flex Coders. This is a direct cut'n'paste so there are some syntax errors.

// faulty example
package whatever {
  public class MySingleton {
    public function MySingleton(singletonEnforcer:MySingletonEnforcer) { }

private static var instance:MySingleton;

pubic function getInstance():MySingleton {
if (instance == null)
instance = new MySingleton(new MySingletonEnforcer());
return instance;
}
}
}

//this is in MySingleton.as but is outside the package block
class MySingletonEnforcer {}

You can defeat this approach with:

var a:MySingleton = new MySingleton(null);
var b:MySingleton = new MySingleton(null);
// a !== b

If you don't know about private classes I wrote up some information. This is just a missing null check in the constructor to make sure that a valid reference was passed in. I like this approach better overall since it has more compile time support. Trying to call "new MySingleton()" gives an "expected 1 argument" compile time error and trying to call "new MySingleton(XXX)" with anything but null will give you a class cast exception. But that is my personal preference.

I'd also recommend that you add final to the class definition. While I'm pretty sure you can't get access to stuff that easily in AS3, it is probably best to guard against subclassing.

If you want to use the first approach, it can be fixed with the introduction of a private method:

package {
    public final class Singleton {
        private static var singleton : Singleton;
		
        public static function getInstance() : Singleton {
            if ( singleton == null )
                singleton = new Singleton( hidden );
            return singleton;
        }
        private static function hidden():void {}	
        //NOTE: AS3 does not allow for private or protected constructors
        public function Singleton( caller : Function = null ) {	
            if( caller != hidden )
                throw new Error ("Singleton is a singleton class, use getInstance() instead");
            if ( Singleton.singleton != null )
                throw new Error( "Only one Singleton instance should be instantiated" );	
            //put instantiation code here
        }
    }
}

The second approach can be fixed with the introduction of a null check:

package whatever {
  public final class MySingleton {
    public function MySingleton(singletonEnforcer:MySingletonEnforcer) {
        if (singletonEnforcer == null) {
            throw new Error ("MySingleton is a singleton class, use getInstance() instead");
        }
    }

private static var instance:MySingleton;

public static function getInstance():MySingleton {
if (instance == null)
instance = new MySingleton(new MySingletonEnforcer());
return instance;
}
}
}

//this is in MySingleton.as but is outside the package block
class MySingletonEnforcer {}

This final example, which I think is best, comes from Daniel Hai via Ted Patrick's JAM. The entry is "Singleton Take 2":


package {
public final class Singleton {
private static var instance:Singleton = new Singleton();

public function Singleton() {
if( instance ) throw new Error( "Singleton and can only be accessed through Singleton.getInstance()" );
}
public static function getInstance():Singleton {
return instance;
}
}
}

I've updated Wikipedia with this last example. Please change it if you notice any problems.

Tags: as3 flex pattern singleton

August 31, 2006

Binding Warning

While working on an AS3 class today I had the following message appear in the debug console:

warning: unconverted Bindable metadata in class 'com.example::SampleData'

Everything still seemed to work correctly, but the fact that the message was getting reported concerned me. Unfortunately, this message doesn't appear in the run-time error documentation, which makes some sense since there was no error number associated with the problem and it just a warning. Doing a little more digging I found that the message is coming from the class mx.binding.BindabilityInfo.as. Thank you Adobe for including sources with the framework!

It seems that when the binding is being resolved the class metadata is bad. In this case the metadata was:

<metadata name="Bindable"/>
<metadata name="Bindable">
<arg key="event" value="propertyChange"/>
</metadata>

The message results from the fact that the first Bindable metadata entry doesn't include an event name. The more important thing was what was causing the event not to exist? Turns out it was a combination of the ordering of my get/set methods and the fact that I was casting my object as an Object instead of as SampleData. A little code will help explain what was going on. First this is the simple application that uses the SampleData instance.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" xmlns:example="com.example.*">
<mx:Script>
<![CDATA[
import com.example.SampleData;
[Bindable]
private var _data:Object = new SampleData();
]]>
</mx:Script>
<mx:Label text="{_data.data}"/>
<mx:TextInput id="textInput"/>
<mx:Binding source="textInput.text" destination="_data.data"/>
</mx:Application>

The reason that _data is cast as an object is that in real code (unlike this simplified example) any one of a number of different types of objects could be fed in as the data to use. Next up is the implementation of SampleData that generates the "unconverted Bindable" error from above.

package com.example {
public class SampleData {
private var _data:Object;
[Bindable]
public function get data():Object {
return _data;
}
public function set data(data:Object):void {
_data = data;
}
}
}

This is where I get really confused about what the compiler and runtime are doing under the scenes. I've not looked at the "-keep" output to see if there is a good explanation. For the time being there are two solutions to the problem. The first one is to switch the order of the getter and setter in SampleData. The following change fixes the Bindable metadata and as such the error goes away:

package com.example {
public class SampleData {
private var _data:Object;
[Bindable]
public function set data(data:Object):void {
_data = data;
}
public function get data():Object {
return _data;
}

}
}

Subtle isn't it :) The [Bindable] documentation shows an example of the setter before the getter, it doesn't seem to emphasize that it can make a difference, which is why I suspect something else funky maybe going on. The other fix is to use more a strongly typed object reference. Using the SampleData class from above with the get before the set, this modified application will also cause the warning to disappear.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" xmlns:example="com.example.*">
<mx:Script>
<![CDATA[
import com.example.SampleData;

[Bindable]
private var _data:SampleData = new SampleData();
]]>
</mx:Script>
<mx:Label text="{_data.data}"/>
<mx:TextInput id="textInput"/>
<mx:Binding source="textInput.text" destination="_data.data"/>
</mx:Application>

Again nice and subtle. If anyone has thoughts on why the order of the getter and setter might contribute to this warning, I'd love to hear them.

Tags: actionscript3 as3 bindable flex warning

July 30, 2006

Flex 2 Runtime Error 1009 and Runtime Modules

While the following error is most often encountered when trying to access a property or function through a null object reference, it can also rear its head when working with runtime modules.

TypeError: Error #1009: Cannot access a property or method of a null object reference.
	at mx.containers::Panel/mx.containers:Panel::layoutChrome()
	at mx.core::Container/mx.core:Container::updateDisplayList()[C:\dev\GMC\sdk\frameworks\mx\core\Container.as:2910]
	at mx.containers::Panel/mx.containers:Panel::updateDisplayList()
	at mx.core::UIComponent/validateDisplayList()[C:\dev\GMC\sdk\frameworks\mx\core\UIComponent.as:5672]
	at mx.core::Container/validateDisplayList()[C:\dev\GMC\sdk\frameworks\mx\core\Container.as:2731]
	at mx.managers::LayoutManager/mx.managers:LayoutManager::validateDisplayList()[C:\dev\GMC\sdk\frameworks\mx\managers\LayoutManager.as:594]
	at mx.managers::LayoutManager/mx.managers:LayoutManager::doPhasedInstantiation()[C:\dev\GMC\sdk\frameworks\mx\managers\LayoutManager.as:646]
	at Function/http://adobe.com/AS3/2006/builtin::apply()
	at mx.core::UIComponent/mx.core:UIComponent::callLaterDispatcher2()[C:\dev\GMC\sdk\frameworks\mx\core\UIComponent.as:7789]
	at mx.core::UIComponent/mx.core:UIComponent::callLaterDispatcher()[C:\dev\GMC\sdk\frameworks\mx\core\UIComponent.as:7732]

The problem seems to be that if the runtime module makes a side-effect reference to a component, which is not included in the main application, it never really gets included in the SWF and as such causes problems when accessed. That's a jumble of words so I think an example is needed.

Create a Flex Application with two files in it. The first one is called com.example.PanelComp.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" width="400" height="300">
    <mx:Text text="Hi"/>
</mx:Panel>

The second one is the main application, call it LoadTest.as:

package {
    import com.example.PanelComp;
    import mx.core.SimpleApplication;

    public class LoadTest extends SimpleApplication {
        private static var panelComp:PanelComp;
    }
}

For more information on that SimpleApplication business check out Roger Gonzalez's blog.

Now in a different Flex Application we want to load the first application and then create an instance of PanelComp.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
    <mx:Script>
        <![CDATA[
            import mx.containers.Panel;
            import flash.utils.getDefinitionByName;

            // must uncomment for "Add Panel" to work
            // TypeError: Error #1009:
            // private static const panel:Panel = null;

            private var _loader:Loader;

            private function loadSwf(location:String):void {
                _loader = new Loader();
                var ctx:LoaderContext = new LoaderContext();
            	ctx.applicationDomain = ApplicationDomain.currentDomain;
            	_loader.contentLoaderInfo.addEventListener(Event.INIT, swfInit);
                _loader.load(new URLRequest(location), ctx);
            }

            private function swfInit(e:Event):void {
                _loader.content.addEventListener("ready", swfLoaded);
            }

            private function swfLoaded(e:Event):void {
                trace("Loaded");
            }

            private function createPanel():void {
                var clazz:Class = Class(getDefinitionByName("com.example.PanelComp"));
                // see note above about TypeError: Error #1009:
                addChild(new clazz());
            }
        ]]>
    </mx:Script>
    <mx:Button label="Load" click="loadSwf('../../LoadTest/bin/LoadTest.swf');"/>
    <mx:Button label="Add Panel" click="createPanel();"/>
</mx:Application>

As noted in the comments, until you uncomment the static reference to Panel in the wrapper application, you will get the stack trace. Something to keep in mind if you are using runtime modules.

Tags: actionscript as3 flex programming

July 30, 2006

Flex 2 Runtime Error 1065

Today while working on some code I started getting this error and stack trace:

ReferenceError: Error #1065: Variable LoadTest is not defined.
	at global/flash.utils::getDefinitionByName()
        at ... (rest of stack trace deleted)

Looking the error up in the documentation didn't help point the way to what might be going on since this had nothing to do with a "variable":

1065 Variable _ is not defined. You are using an undefined lexical reference. For example, in the following statements, the statement trace(x) generates an error because x is undefined. However, the statement trace(y) doesn't generate an error because y is defined: trace("hello world") trace(x) // x is undefined var y trace(y) // No error, y is defined.

In this case I was trying to dynamically instantiate a class by first finding the definition of that class and then newing it. Something like this:

public function createInstance(className:String):Object {
    var instance:Class = Class(getDefinitionByName(className));
    new instance();
}

It turns out the reason why the error was being thrown was that in my Flex Application I didn't have anything which "used" the class. In other words the compiler thought that the class was left over junk and didn't include it in the compiled swf. By adding in a use of it, everything started working. As example use would be something like:

private static const loadTestRef:LoadTest = null;

If there is another way to get this same behavior, please let me know.

Tags: actionscript as3 flex programming

June 30, 2006

Regular Expressions

I've been playing around with Flex 2 for some time at work. One of the neat things that Actionscript 3 adds is native regular expressions. As part of an ongoing effort to share knowledge I volunteered to give an informal talk about regular expressions. To help with the talk I created this visual regular expression viewer. It helps show you what matched along with any groupings and other standard stuff. Additionally it can also perform a regular expression replace operation or a simple split operation.

You will need the Flash 9 in order to run the application.

Launch RegExp Tester!

If you find any bugs, have comments, etc. please leave me a comment.

Tags: actionscript as3 programming regexp regularexpression

June 30, 2006

Interface Constants

Since it has come up a couple of times these past two days, I'm a little disappointed that AS3 interfaces don't support constants. I guess I'm too used to Java's interfaces and really wish AS3 interfaces were as versatile. I've ended up using a class which just has static constants in it to simulate the constants that I would normally have applied to the interface.

If I'm missing some syntax or a better way around this issue, please let me know.

Tags: actionscript as3 flex interfaces

June 30, 2006

AS3 Code Coverage

Note A code coverage tool is now available at http://code.google.com/p/flexcover/.

This maybe a little crazy but I'm going to throw it out there. I've been thinking about a way to get code coverage reports for Actionscript 3. We make heavy use of FlexUnit at work, but I'm always curious just how much of our code is really covered with the tests. I've not found anything about code coverage tools with the few Google searches that I've run hence my search for other solutions.

My current idea is to leverage the Flex debugger. Something along the lines of creating a break point on every line in ever file that you want to check coverage of. As the break points get hit, remove them. Once all of the test code is done running, see if there are any break points that haven't been hit.

This isn't elegant by any means but it should be possible to test the theory with a few hours work. If someone knows of a tool that already does this I'd love to hear about it. Otherwise I'll see how my hacking goes.

Tags: as3 fdb flex testing

June 30, 2006

Dynamic Interface

I would like a way in AS3 to define an interface as being dynamic. In some cases I want all classes that implement an interface to also have to be dynamic. Why might this be useful? I find the chained property accessors much nicer to deal with. I'm not as concerned about adding new methods to the interface and some of the other stuff that you can do with a dynamic class, I just want easy access to unspecified attributes. The fact that you can still use the associative array style lookup on an interface to get the same result only strengthens my belief that you should be able to mark an interface as dynamic.

Since you can't apply the dynamic keyword to an interface and there doesn't seem to be a system interface that endows dynamicness on an interface, you are forced to either use looser typing or use the alternative syntax. I think this calls for an example.

Say I have this interface defined:


package com.example {
public interface ISample {}
}

In another class I have a method that uses that interface:


package com.example {
public class UseSample {
public function displayProp(sample:ISample):void {
trace(sample.prop);
}
}
}

That generates the lovely compiler error:
1119: Access of possibly undefined property prop through a reference with static type com.example:ISample.

If you change the code to use array syntax it will compile:


package com.example {
public class UseSample {
public function displayProp(sample:ISample):void {
trace(sample["prop"]);
}
}
}

In my mind the array syntax is much more obtuse. Oh well, I can always hope :)

Tags: actionscript as3 flex programming

June 30, 2006

Events in Flex 2

Today I got a familiar error while working with some event code:

TypeError: Error #1034: Type Coercion failed: cannot convert flash.events::Event@35f04c1 to com.neophi.events.CustomEvent.

The short answer is that this error results from failing to implement a clone() method on a custom event class. The long answer is that most of the time not implementing a clone() method won't hurt you, based on how you use your custom events, but you really should create one. In fact the Actionscript 3 (AS3) documentation is pretty clear about this:

When creating your own custom Event class, you must override the inherited Event.clone() method in order for it to duplicate the properties of your custom class.

This is a time that I wish AS3 had abstract methods.

Why I say you don't really need a clone() method is that it only becomes an issue if you relay an event. The follow code is an example of event relaying:

private function relay(customEvent:CustomEvent):void
{
    dispatchEvent(customEvent);
}

In this case an event listener redispatches the event that it got. When this happens the event framework behind the scenes calls the clone() method to create a new instance of the event. If you don't have a clone() method and the next listener in the chain is expecting an instance of CustomEvent, the error from above happens. If instead that same listener was only expecting an instance of the Event class, it would work, but any additional information contained in CustomEvent class would be lost, including the ability to cast it to an instance of CustomEvent.

In most cases the clone() method is simple to implement; just transfer any constructor arguments to a new instance of the class. Something like:

override public function clone():Event
{
    return new CustomEvent(_message);
}

Based on the type of event you will probably have more arguments including the all important type and often the other standard event variables for bubbling and cancelability.

While I'm on the subject of events I'll also talk about Event metadata or annotations that you can apply to classes. Often if you have an AS3 class that can emit custom events you will add metadata like this at the top:

package com.neophi {
    import com.neophi.events.CustomEvent;

    import flash.events.EventDispatcher;

    [Event(name="customChange", type="com.neophi.events.CustomEvent")]

    public class EventSource extends EventDispatcher {
        // class code removed 
    }
}

The thing to keep in mind is that depending on how this class will be used you probably don't need that metadata. If this AS3 class isn't used in MXML you can skip the metadata. The metadata is only used to inform the compiler how to translate an MXML event attribute into the appropriate code.

For example with the above class and metadata you could use it in MXML like this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" xmlns:neophi="com.neophi.*">
<mx:Script>
<![CDATA[
import com.neophi.events.CustomEvent;

private function customChanged(customEvent:CustomEvent):void
{
    output.text += "EventTest: " + customEvent + "\n";
}
]]>
</mx:Script>
<neophi:EventSource id="eventSource" customChange="customChanged(event);" />
<mx:Button label="Go" click="eventSource.source();"/>
<mx:TextArea id="output" width="100%" height="400"/>
</mx:Application>

Because cutomChange is defined in the metadata for the EventSource class, in MXML you can now assign a handler to that event. In this case the method customChanged will be called whenever our instance of EventSource dispatches that event.

The method the button is calling to cause eventSource to fire the event is:

public function source():void
{
    var customEvent:CustomEvent = new CustomEvent("Event Message");
    dispatchEvent(customEvent);
}

This code is part of the EventSource class listed above. A new instance of CustomEvent is created and then dispatched. At this point all listeners will get called.

If you tried instead to assign the customChange handler in MXML without the metadata in EventSource you would get a compile error like this:

Cannot resolve attribute 'customChange' for component type com.neophi.events.EventSource.

For events then the two rules of thumb are:

  1. always create a clone() method in any custom event class
  2. add event metadata if you will need to setup handlers for that event in MXML

Tags: actionscript3 as3 events flex programming

May 31, 2006

Flex Beta 3

For anyone following Flex, beta 3 is now available.
From my experience, Flex Builder is much improved but there are still many quirks with it. There were quite a few Actionscript 3 language changes, but the documentation on them is good. My biggest complaint so far is that many MXML files in a Flex library project are not being handled properly by the MXML Editor which results in a complete lack of code assist. The same MXML file in a Flex Application works fine. I've not completely figured out why some of the files are so broken, especially when they seem to work fine on another user's system.

Tags: actionscript as3 flex programming

April 30, 2006

Actionscript 3 FAQ

Mike Chambers is asking for input on improving the Actionscript 3 FAQ.

Tags: actionscript as3 faq programming

April 30, 2006

Flex 2, Actionscript 3, and E4X

I've found a feature of Actionscript 3 (AS3) that I've not seen in other languages that I think is pretty cool. It's taken me awhile to come to terms with it, but now that I've getting more comfortable with it I'm really starting to appreciate it. That feature is what is known as E4X or more officially Standard ECMA-357 ECMAScript for XML (E4X) Specification. At its core is the ability to work with and manipulate XML data in AS3 using standard language syntax instead of having to do everything through an API.

For example to create a variable that contains some hard coded XML you could just write:


var xml:XML =
<componentPackage>
<component id="MyButton" class="package1.MyButton"/>
<component id="MyOtherButton" class="package2.MyOtherButton"/>
</componentPackage>;

Notice the lack of any "new XML("")" or other traditional methods one might use to create an XML document. Pretty cool stuff. You can also do variable substitution when creating XML:


var attributeName:String = "class";
var xml:XML =
<componentPackage>
<component id="MyButton" {attributeName}="package1.MyButton"/>
<component id="MyOtherButton" {attributeName}="package2.MyOtherButton"/>
</componentPackage>;

That creates an XML document that looks exactly like the first XML example. Not the most convincing example, but you get the idea. You can substitute element names, attribute names, or whole attribute values. Besides being able to do inline XML document creation you can also do DOM style navigation to get at elements and attributes within the XML (these return XML or XMLList objects). Going back to the first XML example:


xml.component[0]; // <component id="MyButton" class="com.example.ui.MyButton"/>
xml.component[0].@id; // MyButton

Where things get really cool is the XPath like operations, technically called filters since it isn't as expressive as XPath:


xml.component.(@id == "MyButton"); // <component id="MyButton" class="com.example.ui.MyButton"/>

That searches for all component elements under the root that have an id of MyButton. There are a bunch more. In fact the Working with XML (doc link subject to change) section of the Flex 2 documentation has many good examples. It's at this point that I want to offer a hard learned lesson about what doesn't work with E4X (at present anyway, I can only hope that it will be solved in a future Flex 2 release).

The following line of code doesn't compile (again using the first XML example from above):


xml.component[0].@class; // Error: Expecting identifier before class

The reason is that "class" is a reserved keyword. Thankfully E4X provides alternative attribute access syntax, an example is:


xml.component[0].@["class"]; // package1.MyButton

A little clunky, but still reasonable. What I haven't been able to get working is any of the alternative syntaxes when trying to do a filter using the same attribute:


xml.component[0].(@class == "package1.MyButton"); // Error: Expecting identifier before class

I've tried all four listed variations: element.@attrName, element.attribute("attrName"), element["@attrName"], and element.@["attrName"]. None of them work in the above example, adjusted of course to account for the () filtering operation. This afternoon I finally stumbled upon a solution. This is even more clunky then the alternative attribute accessors, but it does eliminate the need to write custom loops to handle filters like the one above:


xml.component.(@\u0063lass == "package1.MyButton"); // <component id="MyButton" class="com.example.ui.MyButton"/>

In this case I'm using the Unicode value for the letter c (0063) which to my surprise worked. As I said earlier I hope this keyword issue is just a beta issue and it will be resolved. If not, consider using this approach to construct E4X filters that might reference AS3 keywords.

Tags: actionscript as3 e4x flex programmin xml

April 30, 2006

Private or Helper Classes in Actionscript 3

I didn't find this well documented when I was looking it up so I thought I'd post a sample. While Actionscript 3 (AS3) doesn't support protected and private classes like Java does, you can have helper classes that are only visible within the file that they are defined. The syntax for them is a little weird but the Flex 2 Beta 2 compiler seems to like it. The syntax is that after the package you define the helper class:

package com.example {
     public class Sample {
          private var _helperClass:HelperClass = new HelperClass();
     }
}
// imports for the helper class go here
import com.example.xml.SaxHandler;
class HelperClass {
     private var _saxHandler:SaxHandler;
}

Tags: actionscript as3 programming

April 30, 2006

Actionscript 3 Class.forName

I'm sure this would be obvious for anyone that has been programming in Actionscript 3 for awhile, but coming in from the Java world I'm still trying to find the matching idioms. In particular I wanted a way to dynamically load a class based on its name. In Java this is the Class.forName() construct. Luckily AS3 also has a similar mechanism:

// return the class as a Class object
var temp:Class = flash.utils.getDefinitionByName("com.example.Sample") as Class;
// you can now call new it to create an instance along with passing constructor args
var instance:Object = new temp(arg1, arg2, ...);

If when doing this you get an "Runtime Error 1065" see this post.

Note: Update Nov 6, 2007
It looks like flash.util.getClassByName() has gone away. The example above has been updated to use the new mechanism called flash.utils.getDefinitionByName().

Tags: actionscript as3 programming