Here are the findings of my own in-depth research:
Extending the Class class seems to be intrinsically impossible, though this is not well documented anywhere that I've yet seen. From my investigation, I am now convinced that the Class class itself does not include all of the qualities that the other Top Level classes have, even though they all are said to extend from the Object class.
Further frustrating is the fact that subclassing different Top Level classes will result in several different error messages, making it somewhat difficult to tell what issues are at play. To begin with a simple example, if you attempt to subclass many of ActionScript's primitive datatypes (int, uint, Number, String, Boolean, etc), you get the following compiler error:
1016: Base class is final.
This makes sense, because looking at the docs for any of these classes reveals that they are indeed final:
Package Top Level
Class public final class Boolean
Inheritance Boolean -> Object
The final keyword, of course, means that another class may not extend the class marked as final. Now for a more involved example, lets look at an extension of the Function class. The Function class is not final, according to the docs. Since it's not final, does this mean we can extend the Function class to create our own specialized function objects? Here is a definition:
class MyFunction extends Function { /*...*/ }
.. and then at runtime:
VerifyError: Error #1103: Class ::MyFunction cannot extend final base class.
Compare this with the primitive datatype error above. That error happened at compile time, as the inherited primitive class was actually marked as final. The Function class is not marked final but the class still behaves as if it was, only at runtime.
Now, we come to the main question's issue: extending the Class class. As with the Function class, the Class class is not final. Further, the Class class is dynamic, meaning new properties may be added to a Class object at runtime.
As an interesting side-note: The Function class is also dynamic, and I believe this part of what allows for continued support of the old prototypal inheritance mechanisms present in the ECMAscript dialect. In this dialect, Functions are used as classes of a sort (well, prototypes), and the ability for functions to have properties added at runtime is part of the power of prototypal inheritance.
Now, it is my understanding that properties of a Class object are the same as static properties available to any instance of that class. Thus, it should make logical sense that someone might wish to manipulate a Class object at runtime, allowing them to change the behaviour of that class and it's instances. That the Class class is dynamic reinforces this notion.
Since the Class class is not final, I was curious to see if one may extend the Class class, to create their own specialization of the Class model and work somewhere in the meta-language domain. I'll leave for another day the discussion of why someone would want to do this, and what power it would hypothetically allow. Now for the concluding example, let us extend the Class class. Here's a definition:
// the definition causes no errors on its own, even though the compiler "sees" it
class MyClass extends Class { /*...*/ }
/* elsewhere */
MyClass; // the only mention of MyClass beyond the definition
.. and then at runtime:
verify global$init()
stack:
scope:
locals: global
/* snip about 120 lines */
46:getlex 34
stack: global Class$?
scope: global Object$ Class$
locals: global
48:newclass MyClass$cinit()
VerifyError: Error #1107: The ABC data is corrupt, attempt to read out of bounds.
at global$init()
Holy stacktrace! The VerifyError
is reserved for malformed SWF data. Based on what I could find, this is also how a "bug" in the Flash Player tends to manifest. In either case, this is slightly beyond an ordinary ActionScript error.
At this point, it gets rather difficult to understand exactly what is happening, but this is what I've been able to deduce thus far.
VerifyError: Error #1107: The ABC data is corrupt, attempt to read out of bounds.
I (mistakenly, see below comment) believe that "ABC" stands for Abstract Base Class, which is a term applied to classes that cannot be instantiated, only extended. However, the above terrifying error comes not at a point of instantiation, but at the first access of the MyClass Class subclass. In fact, the example's code, I never once instantiate a MyClass object, I only refer to the MyClass class itself.
I did a few further tests and discovered that Class objects do not appear to have constructors, at least, of the sort that typically come from Object subclasses. Simply typing new Class();
anywhere in your code will nicely demonstrate this fact, but you may investigate this further by inspecting the .constructor
property, and with other tricks. As a result of this, instances of the Class class are at best second-class objects, as they cannot be constructed at runtime.
At first I suspected that this was the exact cause of my nasty VerifyError
. However, I now believe that there are many other elements to a class, invisible to our own ActionScript code, that may or may not exist within the Class class, Function class, or other curious places. Certainly, when the Flash Player attempts to access one of those necessary for the extension of a base class, and it doesn't exist (as Class is possibly an ABC, thus missing certain elements present in a normal class), one could well expect to see an out of bounds VerifyError
.
In summary, extending the Class class looks to be impossible at this time. It would appear that the Class class does not include all of the qualities that most of the other Top Level classes inherit from Object, though this is difficult to test.
I would prefer to see a more specific error message result from extending Class, but at the moment there is no such thing. I would love to see some metaprogramming capability return to ActionScript. For now it's good enough to know conclusively that it cannot be done, at least, in this way.