Paul Robertson's words, punctuated

Thoughts on development, user-centered design, code, etc. by Paul Robertson

ActionScript 3 error checking: unit testing recommended

This ended up pretty long, so here’s an executive summary: I’m a big fan of static (compile-time) type checking, so I was a little disturbed to learn that ActionScript 3 differs from AS2 in that it has runtime (dynamic) rather than compile-time (static) type checking. However, once I delved into the issue a bit more, and started applying some principles espoused by Bruce Eckels, I realized that 1. AS3 has very powerful error checking, orders of magnitude beyond what was available previously, and 2. in order to take advantage of that error checking and feel confident that you have a (relatively) error-free AS program, unit testing should now be considered a fundamental part of the ActionScript development workflow.

As I’m sure many of you remember, one of the biggest frustrations of ActionScript 1 stemmed from the fact that it is a weakly typed, dynamically typed language – that is, you don’t specify data types for variables (weakly typed), instead the virtual machine sets the type at runtime (dynamically typed). This often led to hard-to-track-down bugs because the virtual machine treated a variable as a certain type while you assumed the variable was being treated as a different type.

Many years ago I programmed web sites using Microsoft ASP (Active Server Pages) – I’m talking about the original version (a.k.a. “classic” ASP), not the different in all but name ASP.NET. Like ActionScript 1, the VBScript language I used to program ASP pages is a weakly typed language, and it is an interpreted language rather than a compiled language. Unlike in Java or C#, where all the code is compiled before being executed (and therefore all the code has at least been examined for type errors by the compiler), with VBScript a particular branch of code was never even examined by the interpreter unless it was needed. This led to a big issue – if I wasn’t careful to test every possible condition in a particular page, that page could easily be “rolled out” without being fully tested, often with unknown errors. As you may imagine, once I moved to programming Java and C#, I was glad for the static type checking (i.e. type checking at compile time) because I could be assured that every bit of code was examined in order for a successful compile.

Of course, we all know that type checking is only part of the equation, and that it doesn’t account for logical errors in code – but I was happy to have the type checking nonetheless, and I was always hesitant whenever I had to use data structures (such as generic collections) or other operations which require you to add explicit type casts into the code, because those type casts are potential areas of failure at runtime. These are known as operations that are not “type safe” – in fact recent additions to both C# and Java such as generics are specifically designed to remove the need for such structures and make it possible to have type safe code. (And if you’ve read some of my previous articles, you know that even in ActionScript I’m willing to do some extra work to get compile-time type safety with collections.)

So, you may be asking yourself, what does all this have to do with the state of ActionScript in late 2005?

With Flash MX 2004 came ActionScript 2.0, which added static (i.e. compile-time) type checking to the ActionScript language. This was a huge benefit to me, since I’d already learned my lesson with VBScript and moving to strongly typed, statically typed languages. Admittedly, this didn’t reach it’s full potential until the release of MTASC with it’s -strict type checking mode; nevertheless, it was a big benefit. Of course, under the covers it was all compiled down to ActionScript 1, so at runtime the type information was still being figured out by the virtual machine, but in my experience it’s still easier to write code with less bugs in ActionScript 2.0 than in AS1.

However, with ActionScript 3, released in alpha form along with Flex Builder 2, this has changed. As the book “Programming ActionScript 3” (part of the official documentation) points out:

Type checking can occur at either compile time or runtime. Statically typed languages, such as C++ and Java, do all type checking at compile time. As a dynamically typed language, ActionScript 3.0 handles type checking at runtime.

When I first heard this, I got a little bit concerned – as I just described, I’ve become a fan of statically typed languages, so the fact that AS3 is not statically typed is something I saw as an issue. A few paragraphs later, I started to get really worried:

Unlike ActionScript 2.0, ActionScript 3.0 does type checking at runtime instead of compile time. In ActionScript 3.0, explicit type mismatches generate runtime errors. In ActionScript 2.0, the same type mismatch generates a compile time error. The following example shows a function named typeTest that is passed a parameter of the wrong data type. This causes a runtime error because the data type of the variable that is passed as a parameter (int) does not match the parameter’s declared data type (String). If you run this same code using ActionScript 2.0, the type mismatch will generate a compile time error.

function typeTest(xParam:String) {
    trace(xParam);
}
var myNum:Number = 3;
typeTest(myNum);
// Runtime error in ActionScript 3.0, compile time error in ActionScript 2.0

In fact, here are some simpler test cases for the compile-time versus runtime error checking. Create a new ActionScript project in FlexBuilder 2 and paste this code in as the main class:

package
{
    import flash.display.Sprite;
    import flash.util.trace;

    public class TypeCheckingTest extends Sprite
    {
        public function TypeCheckingTest()
        {
            var someInt:Number = "7"; // raises runtime error "Type Coersion failed: cannot convert "7" to Number"
            var someNum:Number = 3;
            typeTest(someNum); // raises runtime error "Type Coersion failed: cannot convert 3 to String"
        }

        public function typeTest(someString:String):Void
        {
            trace(someString);
        }
    }
}

I don’t know about you, but this all looks like a step backwards to me. In AS2 it gives a compile time error (so you find out about the problem immediately) but in AS3 it’s a runtime error (meaning that, like in my past life with ASP/VBScript, if the code is in a conditional branch somewhere it may not get executed and you may have code with obvious type errors that makes it into production, for no other reason than it was decided to make AS3 have dynamic rather than static type checking.

Now, before you type this code into Flex Builder 2 and tell me I’m off my rocker, let me clarify a couple of things. First of all, if you do type this code in and run it, the compiler does in fact give you an error message. So, is the manual wrong? Sort of; I think it would be more correct to say that the manual is just trying to be generic rather than to say that the manual is wrong. You see, by default when you create a Flex or ActionScript project in Flex Builder, the compiler uses a “strict” mode which performs type checking at compile time and flags errors for you. However, if you turn off the strict mode (Project > Properties > ActionScript Compiler > uncheck “Enable compile-time type checking (-strict)”) the code will compile without any errors until you run the movie; at that point you will get a type mismatch error. So the compile-time type checking is an optional feature of Macromedia’s ActionScript compiler, rather than something that is part of the language, so presumably the manual is describing the language regardless of compiler features.

Once I discovered this, things suddenly appeared in a bright new light for me – I realized that with ActionScript 3 we are basically being given the programming equivalent of having our cake and eating it too. For people like me who like to have compile-time type safety enforced, the compiler offers that as an option. However, regardless of the compiler the virtual machine keeps track of and checks the type of objects at runtime, so everybody gets runtime type checking and for those people who prefer to have runtime type checking and not compile-time type checking, they have that option too.

Wait a minute, what did I just say? People who prefer runtime type checking and not compile-time type checking? Does such a person exist?

At one point I didn’t think so (well, at least not among “real” programmers) but a couple of years ago I discovered I was wrong on that point, when I read a well-known article by Bruce Eckel titled ”Strong Typing vs. Strong Testing.” If you are a fan of Python you are likely familiar with this article, as it highlights some of the benefits of that language. If you intend to program in ActionScript 3, I think it is a valuable read, too.

So you don’t have to go off a read that article in order to understand the rest of this one, I’ll attempt to summarize the key points. First of all, the article describes how he (Bruce Eckel) went through a sort of evolution of thought from thinking that static type checking was fundamental for programmer productivity to thinking that it is potentially a hinderence to productivity. He argues that with a statically typed language, programmers can fall into the trap of thinking that because a program compiles, it is correct, which of course isn’t really the case:

If it’s not tested, it’s broken.

That is to say, if a program compiles in a strong, statically typed language, it just means that it has passed some tests. It means that the syntax is guaranteed to be correct … But there’s no guarantee of correctness just because the compiler passes your code. If your code seems to run, that’s also no guarantee of correctness.

The only guarantee of correctness, regardless of whether your language is strongly or weakly typed, is whether it passes all the tests that define the correctness of your program. And you have to write some of those tests yourself. These, of course, are unit tests.

So, as you may gather from the quote, a big part of his change in thinking about the value of static typing versus dynamic typing came about because he started incorporating unit testing as part of his coding process. According to him, one reason dynamic typing is useful is because it allows you to write and test code more quickly, because you aren’t having to fight compiler errors, in particular you aren’t having to create types simply for the sake of satisfying the compiler. He gives a couple of examples (in Python) to demonstrate his point, which I’ll recreate here in ActionScript 3.

This is an example of a "speaking pets" program – a straightforward example of using inheritance in an object-oriented language:

Note: I wrote this article when an early beta of Flex 2 was the current version; the way this code was originally written is no longer valid syntax so I’ve updated it to conform to the final AS3 syntax

// speaking pets in ActionScript 3
package
{
    import flash.display.Sprite;

    public class SpeakingPets extends Sprite
    {
        public function SpeakingPets()
        {
            var pets:Array = [new Cat(), new Dog()];
            for each (var pet:* in pets)
            {
                command(pet);
            }
        }
    }
}

class Pet
{
    public function speak():void
    {
    }
}

class Dog extends Pet
{
    public override function speak():void
    {
        trace("woof!");
    }
}

class Cat extends Pet
{
    public override function speak():void
    {
        trace("meow!");
    }
}

function command(pet:Pet):void
{
    pet.speak();
}

Since this is an ActionScript 3 program, we can have multiple classes defined in a single file, as long as only one (SpeakingPets in this case) is public defined in the package block. Other classes, defined outside the package, are accessible within the .as file but not outside of it. If you’re not used to AS3, the main class’s constructor is the main access point for the program. You can also define functions that live on their own rather than in a class – such as the command() function defined at the end of the code.

Note: I realize that just because you can do something it doesn’t mean you should do it – the command() function could easily have been written as a method in the SpeakingPets class, certainly. The main reason I didn’t do it that way is because it isn’t done that way in the original article, and I wanted to keep the examples parallel as much as possible.

There is a base class, Pet, which has two subclasses, Dog and Cat. Within the main program (the SpeakingPets constructor) an Array instance is created containing a Dog object and a Cat object, and those objects are then passed to the command() function using the new for each loop (I love it!), which calls their respective speak() methods.

The output of this program looks like this:

meow!
woof!

As Bruce demonstrates in Python, we could also create this same program without needing the base class at all. After all, command() really only cares that an object passed to it has a speak() method defined:

Note: I wrote this article when an early beta of Flex 2 was the current version; the way this code was originally written is no longer valid syntax so I’ve updated it to conform to the final AS3 syntax

// speaking pets in ActionScript 3, without base classes
package
{
    import flash.display.Sprite;

    public class SpeakingPetsNoBase extends Sprite
    {
        public function SpeakingPetsNoBase()
        {
            var pets:Array = [new Cat(), new Dog(), new Bob()];
            for each (var pet:* in pets)
            {
                command(pet);
            }
        }
    }
}

class Cat
{
    public function speak():void
    {
        trace("meow!");
    }
}

class Dog
{
    public function speak():void
    {
        trace("woof!");
    }
}

class Bob
{
    public function bow():void
    {
        trace("thank you, thank you!");
    }

    public function speak():void
    {
        trace("hello, welcome to the neighborhood!");
    }

    public function drive():void
    {
        trace("beep, beep!");
    }
}

function command(pet:*):void
{
    pet.speak();
}

Note that we had to make a couple of changes. Most notably, we removed the inheritance artifacts (the base Pet class and the override keywords in the former subclasses) and changed the type of the command() function’s parameter and the iterator variable in the for each loop, both to * (a special type meaning “any type”). As in Bruce Eckel’s original example, there’s a new Bob class (which of course isn’t a pet at all), since a Bob is something that can speak just as well as a pet.

You could also leave the type off completely rather than using *, which will generate a warning unless you turn off the compiler warnings but won’t prevent the file from compiling. Untyped variables are automatically given the type * by the compiler.

When we run this program, the output looks like this:

meow!
woof!
hello, welcome to the neighborhood!

So in AS3, like Python, we can circumvent type checking at compile time simply by using a variable of type Object (or with no type, meaning the compiler sets its type to Object for us). If you’re used to static typing, this could look a little disconcerting; but on the other hand, there have been times that I’ve found myself wishing I could write code calling a method with the same name on various objects, without needing to make them all inherit from the same base type. (come on now, admit it, you’ve found yourself thinking that at least once before…) Nevertheless, it still looks like it could be error-prone; after all, anyone could pass any object into the “command” function. What if it that object doesn’t have a “speak” method? What will our program do? Let’s try it and see! Let’s add a new class definition:

class Tuba
{
    public function play()
    {
        trace("blat!");
    }
}

Make sure to create an instance of our new Tuba class to pass in to the function–change the Array constructor call as follows:

var pets:Array = [new Cat(), new Dog(), new Bob(), new Tuba()];

Compile the code – it works fine, no errors. Run the code, and this is the result:

meow!
woof!
hello, welcome to the neighborhood!
ReferenceError: Error #1069: Property speak not found on SpeakingPetsNoBase.as$0.Tuba and there is no default value

Flash Player recognizes the fact that a Tuba object can’t speak, it just does so at runtime rather than the compiler doing so at compile time. Notice that the other object’s speak() methods were all called before the error was triggered. So the key issue isn’t the lack of error checking anymore; instead, the issue is just making sure that every line of code we write, every branch of every conditional, actually gets tested before we hand off the program and call it done. Going back to Bruce’s article, he says that even without compile-time error checking it is still possible to create error-free code because of “strong testing” – consistent and thorough use of unit tests to ensure that all your code paths get run and tested:

Some Java tests happen at compile time (syntax checking), and some happen at run time (array-bounds checking, for example). Most Python tests happen at runtime rather than at compile time, but they do happen, and that’s the important thing (not when). And because I can get a Python program up and running in far less time than it takes you to write the equivalent C++/Java/C# program, I can start running the real tests sooner: unit tests, tests of my hypothesis, tests of alternate approaches, etc. And if a Python program has adequate unit tests, it can be as robust as a C++, Java or C# program with adequate unit tests (although the tests in Python will be faster to write).

I don’t want to give any wrong impressions here. I am certainly not trying to start a language war, or advocating for or against the use of Python or any other dynamically typed language. However, the creators of ActionScript 3 (Macromedia) have decided that AS3 will be like Python in the sense that it is a language which uses runtime type checking. Whether or not you choose to use the “strict” compiler option which shows type errors at compile time (personally I still plan to use it), there are limits to the checking that it can provide, and ultimately AS3 is intended to be a runtime-checked language. If you want to ensure that your AS3 code will not generate any errors, or that it at least handles those errors gracefully, unit testing is the best way to do that.

Recently I’ve started working on migrating a code library (my XML-RPC client for ActionScript) to ActionScript 3. Almost immediately after the thought crossed my mind that I would need to migrate it to AS3, my next thought was “I’m going to need to write some unit tests for this.” And that was even before most of the thinking that led to this article. I don’t plan on making major changes immediately, at least not in the first attempt, but there are some obvious areas of potential improvement that will be available for the AS3 version (such as using E4X and the new reflection mechanisms) so when I’m doing that refactoring I’m going to be leaning heavily on unit tests to help me feel safe about the changes I make to the code.

I’m sure that those of you who are already “test-infected” are thinking that I’m just repeating what you’ve been saying for years. And you’re probably right–I wouldn’t argue that point, especially since I’m quoting an article that was written some time ago. Admittedly, when I first read Bruce Eckel’s article a couple of years ago, I thought his arguments were sound, but since at that time I did my programming in statically typed languages, I wasn’t in a position to try out the benefits he argues for, so I just put it aside for another day, I guess. Once I learned that AS3 uses dynamic type checking, I realized that as an AS3 developer I fall squarely in the target audience of his article, so that was the “tipping point” to get me on the unit testing bandwagon. What can I say…most unit-testing advocates have a story, now I have mine too, I guess.

For your further researching pleasure I know of two unit testing frameworks for AS2:

  • ASUnit - an open source project spearheaded by Luke Bayes and Ali Mills. This is designed for ActionScript 2, with support for MTASC/FAME as well as Flex. They’ve just posted an alpha version with AS3 support.
  • AS2Unit (and Flex Unit for Flex) - written by the former Iteration::Two crew (now Macromedia Consulting Europe).

I’ve already started using ASUnit, and since they’ve already added AS3 support, I will be using that for my migration project, and for other AS3 projects that I’ve started cooking up. I’d be interested to hear feedback from others who’ve used it, especially for AS3, or any alternatives that you know about.

Comments