In AS3, you can create an Array can be created with special syntax: myArray = []. You can even fill the Array with values all in one go: myArray = [1,2,3,4,5]. This is a nice shorthand that saves some typing compared to using the constructor: myArray = new Array(1,2,3,4,5). But, which way is faster? Today we find out! UPDATE: added a third way of creating arrays

I’ve covered declaring Vectors before, but today’s article asks the same sort of questions for Array: how should we declare them for optimal speed? To reduce typing, the choice is clear. Code clarity is, as usual, subjective and I won’t cover that topic here. Instead, let’s look at a couple of examples:

var a:Array;
a = [];
a = new Array();

Now let’s look at the bytecode that’s generated by these two Array initializations:

// a = []
newarray      	[0]   // create the Array
coerce        	Array // make sure it is typed Array
setlocal1     	      // set it to a
 
// a = new Array()
findpropstrict	Array     // find the Array class
constructprop 	Array (0) // call the constructor
coerce        	Array     // make sure it is typed Array
setlocal1     	          // set it to a

First off, we have a savings of one instruction in the SWF for using the shorthand. This is because we’re taking advantage of a specialized bytecode—newarray—rather than relying on the generalized constructor-calling bytecodes. We also avoid the search for the Array class.

There is a third way as well. A function taking var args (...) has its var args transformed into an Array. This Array can simply be returned. This gives rise to a utility function:

function createArray(...rest): Array
{
	return rest;
}

How fast are all of these options? Well, let’s do a test to compare creating Array objects with zero, five, ten, and twenty elements:

package
{
	import flash.display.*;
	import flash.utils.*;
	import flash.text.*;
 
	public class ConstructingArrays extends Sprite
	{
		public function ConstructingArrays()
		{
			var logger:TextField = new TextField();
			logger.autoSize = TextFieldAutoSize.LEFT;
			addChild(logger);
 
			var beforeTime:int;
			var afterTime:int;
			var i:int;
			const REPS:int = 1000000;
			var a:Array;
 
			logger.text = "new,[],var args\n";
 
			logger.appendText("0,");
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				a = new Array();
			}
			afterTime = getTimer();
			logger.appendText((afterTime-beforeTime) + ",");
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				a = [];
			}
			afterTime = getTimer();
			logger.appendText((afterTime-beforeTime) + ",");
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				a = createArray();
			}
			afterTime = getTimer();
			logger.appendText((afterTime-beforeTime) + "\n");
 
			logger.appendText("5,");
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				a = new Array(1,2,3,4,5);
			}
			afterTime = getTimer();
			logger.appendText((afterTime-beforeTime) + ",");
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				a = [1,2,3,4,5];
			}
			afterTime = getTimer();
			logger.appendText((afterTime-beforeTime) + ",");
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				a = createArray(1,2,3,4,5);
			}
			afterTime = getTimer();
			logger.appendText((afterTime-beforeTime) + "\n");
 
			logger.appendText("10,");
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				a = new Array(1,2,3,4,5,6,7,8,9,10);
			}
			afterTime = getTimer();
			logger.appendText((afterTime-beforeTime) + ",");
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				a = [1,2,3,4,5,6,7,8,9,10];
			}
			afterTime = getTimer();
			logger.appendText((afterTime-beforeTime) + ",");
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				a = createArray(1,2,3,4,5,6,7,8,9,10);
			}
			afterTime = getTimer();
			logger.appendText((afterTime-beforeTime) + "\n");
 
			logger.appendText("20,");
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				a = new Array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
			}
			afterTime = getTimer();
			logger.appendText((afterTime-beforeTime) + ",");
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
			}
			afterTime = getTimer();
			logger.appendText((afterTime-beforeTime) + ",");
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				a = createArray(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
			}
			afterTime = getTimer();
			logger.appendText((afterTime-beforeTime) + "\n");
		}
 
		private function createArray(...rest): Array { return rest; }
	}
}

I then ran the test in this environment:

  • Flex SDK (MXMLC) 4.1.0.16076, compiling in release mode (no debugging or verbose stack traces)
  • Release version of Flash Player 10.2.154.25
  • 2.4 Ghz Intel Core i5
  • Mac OS X 10.6.7

Here are the test results I got:

new [] var args
0 241 206 215
5 422 256 274
10 834 318 337
20 1498 410 426

You can see from the table that the [] operator consistently beats the new operator (constructor) approach. The createArray/var args method also beats it, but is consistently edged out by the [] operator. However, a graph of the performance as elements increase really shows how badly the constructor version scales:

Performance Chart

So we’ve seen that the [] operator is better than the constructor in amount of typing required, bytecode generated, and run-time performance at all lengths. Do keep this in mind if you’re still using Array, such as in cases where Flash 9 support is still required or you’re just looking for better performance with sorting.