Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it legal to extend the Class class?

I've been writing a system that at runtime generates some templates, and then generates some objects based on those templates. I had the idea that the templates could be extensions of the Class class, but that resulted in some magnificent errors:

VerifyError: Error #1107: The ABC data is corrupt, attempt to read out of bounds.

What I'm wondering is if subclassing Class is even possible, if there is perhaps some case where doing this would be appropriate, and not just a gross misuse of OOP. I believe it should be possible, as ActionScript allows you to create variables of the Class type. This use is described in the LiveDocs entry for Class, yet I've seen no mentions of subclassing Class.

Here's a pseudocode example:

class Foo extends Class

var A:Foo = new Foo(); // A is a class
trace(A is Class); // true, right?
var b = new A(); // b is an instance of class A

I have no idea what the type of b would be. Would it be this?

trace(b is A); // true?

But then, could you type the variable b to type A, as in var b:A = new A();, even though A doesn't exist until runtime? I have read that this is not possible as A is not statically resolvable, but I am doing my own tests to explore this possibility.

Ultimately, the purpose is to generate new classes at runtime, and to then create instances of those classes.

In summary: can you subclass the Class class? If so, how can you do it without errors, and what type are the instances of the instances of the Class subclass?

like image 903
ivanreese Avatar asked Apr 10 '10 18:04

ivanreese


People also ask

Can a class extend another class?

The extends keyword extends a class (indicates that a class is inherited from another class). In Java, it is possible to inherit attributes and methods from one class to another. We group the "inheritance concept" into two categories: subclass (child) - the class that inherits from another class.

What classes Cannot be extended?

A final class cannot extended to create a subclass. All methods in a final class are implicitly final . Class String is an example of a final class.

How many classes can a class extend?

A class can extend only one class, but implement many interfaces. An interface can extend another interface, in a similar way as a class can extend another class.

What happens if final class is extended?

The main purpose of using a class being declared as final is to prevent the class from being subclassed. If a class is marked as final then no class can inherit any feature from the final class. You cannot extend a final class. If you try it gives you a compile time error.


2 Answers

From the livedoc in the first paragraph it states Every Class object is an instance of the Class class. Therefore, it would be an error to extend Class as any class object already is a Class.

You said a system that generates some templates, and then generates some objects based on those templates. It sounds like what you are really trying to do is create an interface.

An interface should be used when your template does not provide any implementation. That is, you declare a bunch of fields and methods but provide no implementation of the methods. You would declare such a class as follows:

public interface Foo {
    function bar:void;
}

Now to create a class that implements this interface you simply do the following.

public class MyClass implements Foo {
    function bar:void {
        ..... implementation goes here .....
    }
}

It is possible for a class to implement multiple interfaces, while it may extend only one class.

If however, you want to provide any implementation in your template class then it is likely that you are best off just creating a class that has any commonalities that its subclasses have and just use plain old inheritance.

Hope this helps.

like image 150
Matt Avatar answered Oct 02 '22 22:10

Matt


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.

like image 41
ivanreese Avatar answered Oct 02 '22 22:10

ivanreese