mike chambers | about

Using Vectors in ActionScript 3 and Flash Player 10

Tuesday, August 19, 2008

One of the new ActionScript features included in the Flash Player 10 Public Beta is the inclusion of a Vector class. Essentially, the Vector class is a typed Array, and in addition to ensuring your collection is type safe, can also provide (sometimes significant) performance improvements over using an Array.

Using the Vector class is pretty simple, and very similar to using an Array. In fact, the Vector class contains all of the same methods as the Array class. The main difference is how you instantiate it.

For example, here is how you instantiate an Array:

var a:Array = new Array();
//or
var b:Array = [];

Here is an example of instantiating a Vector that contains int types:

//var VARIABLENAME:Vector.<VECTORTYPE> = new Vector.<VECTORTYPE>();
var vector:Vector.<int> = new Vector.<int>();

Just as in an Array, you can initialize the Vector length to a specific size, by passing the length into the constructor:

var size:int = 7;
var vector:Vector.<int> = new Vector.<int>(size);

However, the Vector has an additional constructor argument, which is a Boolean value that specifies whether the Vector size is fixed (true) or can be changed (false). The default value is false, and the property can be changed with the fixed property:

var size:int = 7;
var fixed:Boolean = true
var vector:Vector.<int> = new Vector.<int>(size, fixed);
vector.fixed = !fixed;

Keep in mind, that if fixed is set to true, then you cannot call any Vector methods that change the length, such as pop(), push(), shift(), etc…

Vectors are also type safe, so while with an Array you can store multiple types:

var s:String = "I am a string";
var d:Date = new Date();  
var n:Number = 1138      
var a:Array = new Array();
a[] = s;
a[1] = d;
a[2] = n;

trace(a[1] is Date); //true

You will get a compile time TypeError with a Vector:

var s:String = "I am a string";
var d:Date = new Date();  
var n:Number = 1138      
var v:Vector.<String> = new Vector.<String>;
v[] = s;
v[1] = d;
v[2] = n;

trace(v[1] is Date); //false

//Compile time errors:
//Implicit coercion of a value of type Date to an unrelated type String.   
//Implicit coercion of a value of type Number to an unrelated type String. 

Other than that, working with a Vector is pretty much the same as working with an Array. The APIs are the same, and you can access items directly via their index.

var vector:Vector.<int> = new Vector.<int>();

var rand:Number;
for(var i:int = 0; i < 1000000; i++)
{
    rand = (Math.floor(Math.random() * 1000000) as int);
    vector.push(rand);
}

trace(vector[7]);

One last thing to keep in mind is that a Vector is basically a dense array. This means that all items in the Vector must have either a value or null.

For example, with an Array, you can do this:

var a:Array = new Array();
a[] = "foo";
a[6] = "bar";

But if you try that with a Vector:

var v:Vector.<String> = new Vector.<String>();
v[] = "foo";
v[6] = "bar";

You will get a RangeError at runtime.

The fix is to initialize the Vector length:

var v:Vector.<String> = new Vector.<String>(7);
v[] = "foo";
v[6] = "bar";

Below is an example that shows a difference in performance in looping over a million numbers in a collection. Keep in mind that this is one specific test, and depending on your use case, performance improvements may be greater or smaller.

package
{
    import flash.display.Sprite;

    public class VectorTest extends Sprite
    {
        private static const NUM_LOOPS:int = 5;
        public function VectorTest()
        {   
                        
            var vector:Vector.<int> = new Vector.<int>();
            var array:Array = new Array();
            
            //populate data
            var rand:Number;
            for(var i:int = 0; i < 1000000; i++)
            {
                rand = (Math.floor(Math.random() * 1000000) as int);
                vector.push(rand);
                array.push(rand);
            }
            
            var sTime:Number = getMilliseconds();
            loopArray(array);
            trace("Loop Array Avg (5) : " + ((getMilliseconds() - sTime)/NUM_LOOPS));

            sTime = getMilliseconds();
            loopVector(vector);
            trace("Loop Vector Avg (5) : " + ((getMilliseconds() - sTime)/NUM_LOOPS));

        }
        
        private function getMilliseconds():Number
        {
            return (new Date()).getTime();
        }
        
        private function loopArray(a:Array):void
        {
            var len:Number = a.length;
            
            var n:int;
            for(var i:int = 0; i < NUM_LOOPS; i++)
            {
                for(var k:int = 0; k < len; k++)
                {
                    n = a[k];
                }
            }
        }
        
        private function loopVector(v:Vector.<int>):void
        {
            var len:Number = v.length;
            
            var n:int;
            for(var i:int = 0; i < NUM_LOOPS; i++)
            {
                for(var k:int = 0; k < len; k++)
                {
                    n = v[k];
                }
            }
        }
    }
}

On my machine, I get this output:

Loop Array Avg (5) : 115.8
Loop Vector Avg (5) : 108.8

Which is significant given the simplicity of the test (just referencing the value).

You can find more information on Vectors in the Flash Player 10 Beta documentation.

You can find more information on Flash Player 10 on labs.

twitter github flickr behance