Hack 75 Strict Typing and Casual Scripters

figs/moderate.gif figs/hack75.gif

ActionScript 2.0 introduces strict typing to check for incorrect datatypes. Strict typing can help motion graphics developers spend less time debugging and more time being creative.

ActionScript 2.0 introduces strict typing to detect datatype mismatches at compile time. Should you use strict typing if you're a motion graphics scripter and not a hard-core application developer creating object-oriented programs using classes? The answer is a resounding "yes." Motion graphics is predominantly about speed and responsiveness, and all developers want to spend less time debugging and more time being creative. Strict typing lets you perform less runtime checking, which improves performance, and the compile-time checks catch potential errors that would cause silent failure in Flash MX.

So you get better, more robust code using ActionScript 2.0 type checking, even if your code is brief and doesn't use object-oriented techniques. The additional type checking makes it more likely your code will work correctly once it compiles successfully, and there is no runtime performance hit [Hack #100] .

How Strict Typing Helps

Let's have a look at how to implement some ActionScript 2.0 code and how strict typing helps when scripting motion graphics.

function makeDot(clip:MovieClip):Void {

  // Make a dot within clip

  clip.lineStyle(10, 0x0, 100);

  clip.moveTo(0, 0);

  clip.lineTo(1, 0);

}

function mover( ):Void {

  // Move the dot

  this.sX = checkLimits(this.sX, this._x, 0, 550);

  this.sY = checkLimits(this.sY, this._y, 0, 400);

  this._x += this.sX;

  this._y += this.sY;

}

function checkLimits(speed:Number, limit:Number, 

                     low:Number, high:Number):Number {

  // Reverse direction when the dot hits an edge of the screen

  if ((limit < low) || (limit > high)) {

    return -speed;

  } else {

    return speed;

  }

}

var ball:MovieClip;

for (var i:Number = 0; i < 100; i++) {

  ball = this.createEmptyMovieClip("dot" + i, i);

  ball._x = Math.random( ) * Stage.width;

  ball._y = Math.random( ) * Stage.height;

  ball.onEnterFrame = mover;

  ball.sX = Math.random( ) * 8 + 2;

  ball.sY = Math.random( ) * 8 + 2;

  makeDot(ball);

}

Notice that var ball:MovieClip; declares the ball variable to be an instance of the MovieClip class (this is synonymous with saying that ball is of type MovieClip because a class declaration effectively defines a custom datatype of the same name). Specifying ball's type as MoveClip tells the compiler that the variable must contain a movie clip reference. We later use the ball variable to store a reference to the clip created at runtime with createEmptyMovieClip( ), such as clips dot0, dot1, and so on.

Notice that the datatype is specified after a colon, and whenever you define a datatype for a variable, the variable must be preceded by the var keyword.

If we try to assign a value that is not a movie clip reference, such as:

ball = 0;

ball = "dot+i";

the Flash compiler displays a type mismatch in the Output panel. Fixing it during authoring is easy and fast, whereas omitting the type checking would leave us staring at a blank Stage at runtime, wondering where the problem might lie.

Notice in the preceding example that the functions and event handlers are also typed. A function that doesn't return any value should be given a return type of Void (with a capital "V"):

function myName( ):Void {

  // Do stuff

};

If the preceding function returns a value, which it shouldn't, Flash displays an error at compile time.

A function that accepts arguments and returns a value is written like this:

Function myName(argument:argType):returnType {

  // Do stuff

  return someValue;

};

If we try to pass it an argument that is of the wrong datatype or if it returns the wrong datatype (i.e., if someValue isn't of the datatype specified by returnType), Flash again provides a compile-time error.

Using strict type checking helps the Flash compiler catch many bugs that would have caused runtime problems in Flash MX. ActionScript 2.0 strict typing helps to confine errors to one code block (such as a function or event handler) to prevent errors from propagating to other code that calls the problematic code.

Limitations of Strict Typing

Strict typing can't be quickly and easily used in all cases. Let's look at some of the limitations of compile-time type checking.

Dynamic properties are not type checked

Notice that in the preceding example, ball.sX and ball.sY are specified without a datatype. You cannot use the var keyword when you attach custom properties to a clip dynamically at runtime. Not being able to use var also means that you can't specify their datatype. Furthermore, because an untyped variable is allowed to be of any datatype, the Flash compiler wouldn't complain about the following (even though we intend ball.sX to hold a number not a string):

ball.sX = "cat";

Even though ball.sX is eventually accessed as this.sX inside the mover( ) function and passed to the checkLimits( ) function as a parameter named speed, where it is strictly typed as Number, Flash's compile-time validation can't detect such indirect errors. An untyped variable passes through all checks with no errors.

If you want to use strict typing to validate the datatype of properties, you have to create a custom class. You can then define the type of each class property or instance property within the class definition. For example, you can place this code in an external Ball.as file to create a custom Ball class that subclasses the MovieClip class:

// This ActionScript 2.0 code must go in an external Ball.as file

class Ball extends MovieClip {

  var sX:Number;

  var sY:Number;

}

Then, revising the earlier code example, you can declare the ball variable to be of type Ball instead of type MovieClip:

var ball:Ball;

Because of the class definition, Flash will perform type checking on instance properties such as ball.sX and ball.sY.

Conditional statements confuse type checking

Flash supports only compile-time type checking, so it does not run the code when it performs type checking. Therefore, it cannot detect cases involving return statements within conditional expressions. If an if statement is structured as follows, the checkLimits( ) function won't return a value even though its return datatype is specified as Number:

function checkLimits(speed:Number, limit:Number, 

                     low:Number, high:Number):Number {

  if (false)) {

    return -speed;

  } 

};

But Flash checks only the datatype of the expression following the return keyword, in this case -speed, and the preceding code does not cause a compile-time error.

Final Thoughts

ActionScript 2.0 provides type checking unavailable in ActionScript 1.0, without affecting runtime performance or complaining about untyped variables (i.e., it won't choke on legacy ActionScript 1.0 code that hasn't been updated to ActionScript 2.0). Type checking helps you write correct, robust code by catching errors you might otherwise miss.

Although ActionScript 2.0 doesn't perform type checking at runtime and author-time type checking can't be quickly implemented in all cases, using type checking whenever possible saves scripters of all levels considerable time and aggravation.