That’s about as good a title as I could come up with here. πŸ™‚

Background

Let’s say you have a function expecting …rest arguments. Firstly, if you’re not familiar with …rest arguments, read this. Here is a code example of the issue (hand-written and untested):

protected function fun1(...rest):void{
	fun2.apply(null, rest);
}
 
protected function fun2(some:*, thing:*, here:*, ...rest):void{
	trace(some, thing, here, rest);
}
 
fun1("here", "are", "my", "args", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

This code passes 14 arguments to fun1, which is completely legit. fun1 then passes all 14 arguments to fun2. The trace output would be:

"here", "are", "my", "args", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

That’s easy, right? Β Let’s throw a monkey wrench in this puppy real quick.

The Problem

Taking the previous example, let’s swap the calls. fun2 will not call fun1 and the initial function call will be to fun2. Here is the code:

protected function fun1(...rest):void{
	trace(rest);
}
 
protected function fun2(some:*, thing:*, here:*, ...rest):void{
	var newArg:* = 1;
	fun1.apply(null, [some, thing, here, newArg, rest]);
}
 
fun2("here", "are", "my", "args", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

Now, you may say: “What’s wrong with that?” To that I’d say: “A LOT!” The monkey wrench is newArg. See, apply(..) takes an array as the second argument which works well unless you’re passing in rest.

The trace would be:

"here", "are", "my", "args", [1, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]

This is very subtle but notice the last part of the trace is a multidimensional array consisting of newArg and the rest argument passed from fun2.

A Solution

This is a quick and easy way to solve this problem. What you want to do is actually pass in every argument in the rest argument as a single argument, not as an array, but we’re still passing in an array to the apply(…) function. Here is one way to tackle this puppy using array manipulation:

protected function fun1(...rest):void{
	trace(rest);
}
 
protected function fun2(some:*, thing:*, here:*, ...rest):void{
	var newArg:* = 1;
	fun2.apply(null, [some, thing, here, newArg].concat(rest));
}
 
fun2("here", "are", "my", "args", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

Ahh…notice the second line of the fun2 function. we’re passing in an array of arguments and concatenating the rest argument with the arguments array.

Here is the output trace from that:

"here", "are", "my", "args", 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

That is exactly what you want to see, in this case. πŸ™‚

Conclusion

This one just bit me in the butt so I thought I’d blog it to help someone else.

What other ways do you use to solve this problem? I’m sure this isn’t the only way.