Download

Go here to download ready-to-run and source distributions of Jangaroo. more...

Monday, January 30, 2012

Simulating ActionScript Rest Parameter in JavaScript

Let's continue the series on simulating ActionScript language features in JavaScript with something similar to optional parameters, namely the ... (rest) parameter.
ActionScript allows you to specify that an arbitrary number of parameters follow the usual named and optional parameters by prefixing the last parameter with three dots (see "The ... (rest) parameter"):

 1 public function join(separator:String, first:String,
                        ...strings:Array):String {
 2   strings.splice(0, 0, first);
 3   return strings.join(separator);
 4 }

As you can see, all formal parameters following the named parameters are combined into an array. Since the ... (rest) parameter is always of type Array, you can safely skip the type annotation.

The arguments variable in JavaScript
Fortunately, JavaScript offers access to all formal parameters of a function call, even if they are not declared as named parameters of the function, through the arguments variable. For some reason, this variable does not actually hold an Array. Instead, it is an array-like Object with indexed properties and a length property. This means that we cannot invoke Array methods directly on arguments, but there is a trick: Call the slice function retrieved from the Array prototype, as described e.g. here, and the result is a "real" Array:

Array.prototype.slice.call(arguments)

At the same time, we can cut off the named parameters, since the first parameter to slice is the index where to start slicing from the source array. Thus, the resulting JavaScript code generated by the Jangaroo compiler jooc is the following:

 1 function join(separator, first) {
     var strings = Array.prototype.slice.call(arguments,2);
 2   strings.splice(0, 0, first);
 3   return strings.join(separator);
 4 }

Note the slice parameter value 2, which takes care of cutting off the two named parameters. Also note how Jangaroo only adds an auxiliary statement, but keeps all other statements exactly the same, which makes debugging a lot easier.

Side note: arguments is an array is AS3
The only thing Jangaroo currently does not yet implement correctly is that in ActionScript, the arguments variable is actually always an array! Thus, instead of writing

 1 public function joinComma() {
 2   return arguments.join(",");
 3 }

which would be fine in ActionScript, in Jangaroo you currently have to use

 1 public function joinComma(...args) {
 2   return args.join(",");
 3 }

This is to save the overhead of always converting arguments into an array. Of course, the compiler could analyze whether arguments is used as an Array at all and only add the conversion code then. I just filed the bug as issue JOO-12.

0 comments: