Today I spent a whole morning to figure out that AS3 sucks.
Today I’ve been implementing a simple factory method which receives a Class object and some parameters to be passed to the concrete class instance, something with a signature like this:
static public function createInstance(c:Class, ... args):Object
BUT…the implementation of such a clear and simple method has been a bloody bath, because AS3 doesn’t support a really cool way to do really cool stuff like this ![]()
I thought the implementation would be simply something like
static public function createInstance(c:Class, ... args):Object
{
return new c(args);
}
or any other easy way (python taught me to think simple
) BUT…
“new c(args);” means my class constructor accepts one parameter typed as an Array, and I really don’t want my custom classes to have this defect of form nor my custom factory not to be able to instance classes written by someone else, so the solution “classes to be instanciated by the factory must accept an array as constructor parameter” is absolutely out.
Next approach, “reflect all properties instead of having parameters passed to the constructor”… not really a solution. Not always classes’ properties have the same name\type\whatever of constructor parameters. It’s a compromise that my factory can’t accept because I wouldn’t be able to create whatever class instance but only “some” class instance :\. out.
Next approach, “use Function.apply to pass some parameters (array) to a function as they were single variables”..hey! that’s a good one! Let’s try it with some function
class MyClass{
public function myfunc(foo:String,bar:uint):void
{
trace(foo, bar);
}
}
class MyOtherClass{
public function callmyfunc(... args):void
{
var c:MyClass = new MyClass();
c.myfunc.apply(null,args);
}
}
HEY! IT WORKS! holy crap! AS3 rocks!…wait, let’s try it with a constructor function…
class MyClass{
public function MyClass(foo:String,bar:uint):void
{
trace(foo, bar);
}
}
class MyOtherClass{
public function callmyfunc(... args):void
{
var c:MyClass = new MyClass().apply(null,args);
}
}
…ok, it doesn’t work :\ and throws a runtime error :/ “Property apply not found on MyClass and there is no default value”…mmm
ok, maybe I have to reference the constructor function, but how can I do it!?
let’s try with “Class.prototype.constructor”
class MyClass{
public function MyClass(foo:String,bar:uint):void
{
trace(foo, bar);
}
}
class MyOtherClass{
public function callmyfunc(... args):void
{
var c:Class = MyClass;
var f:Function = c.prototype.constructor;
}
}
…error… Class.prototype.constructor returns the type of the caller class (in this case MyClass)…
so…what can I do?
Discarded solutions:
- “classes to be instanciated by the factory must accept an array as constructor parameter”
- “reflect all properties instead of having parameters passed to the constructor”
- “use Function.apply to pass some parameters (array) to a function as they were single variables”
here’s the solution: (drums) THE CRAPY ONE!
better known as “switch it all baby”….
static public function create(c:Class, ... args):Object {
switch(args.length){
case 0: return new c();
case 1: return new c(args[0]);
case 2: return new c(args[0],args[1]);
case 3: return new c(args[0],args[1],args[2]);
case 4: return new c(args[0],args[1],args[2],args[3]);
case 5: return new c(args[0],args[1],args[2],args[3],args[4]);
default: throw new Error("too many arguments");
}
return null;
}
if you need to pass more than 5 arguments just add some lines to the factory and you’re done…
I was completely pissed off when I found this horrible lack in AS3, really, I was about for starting to cry, so I submitted a feature request on bugs.adobe… I think it’s really a MUST for a “respectable” language, if you find it as necessary as I think take a minute to vote this feature.
https://bugs.adobe.com/jira/browse/FP-3364