package { public interface IMyInterface { function myFunction( singular: String, ... varargs ): void; } }
If we're implementing a basic Decorator-style pattern to extend some functionality, we're going to want to pass the parameters on to the child unaffected. If we tried the following:
package { public class NewFeature implements IMyInterface { private var _child: IMyInterface; public function NewFeature( child: IMyInterface ) { _child = child; } public function myFunction( singular: String, ... varargs ): void { _child.myFunction( singular, varargs ); } } }
Then the varargs will get passed to the child function's varargs parameter as a single array, rather than the unrolled varargs. That is, assuming we had the following:
package { public class CoreFeature implements IMyInterface { public function myFunction( singular: String, ... varargs ): void { trace( "Singular: " + singular ); trace( "Varargs: " + varargs ); } } }
and then made a call as per:
var feature: IMyInterface = new NewFeature( new CoreFeature( ) ); feature.myFunction( "foo", "bar", "qwerty", "asdf" );
Then the debug console would contain the following output:
Singular: foo Varargs: [ [ bar, qwerty, asdf ] ]
That is, when passing the varargs variable to a function call, it is treated as an array. Thus, when it is passed on to a varargs parameter, it becomes the first element of the subsequent varargs array.
The fix here is to use some basic runtime reflection to call the function, rather than invoking it directly. By using the Function.apply() method, we're able to pass an array of parameters into the function call. AVM2 will correctly match up the explicit parameters, and then group the rest into the varargs variable. For example:
package { public class NewFeature { private var _child: IMyInterface; public function myFunction( singular: String, ... varargs ): void { varargs.unshift( singular ); _child.myFunction.apply( _child, varargs ); } } }
In this example, we need to stick singular at the start of the array, so that it is correctly applied to the child function.
Calling the function as per the example above, would now result in the following debug console output:
Singular: foo Varargs: [ bar, qwerty, asdf ]