Make your own free website on Tripod.com

Inheritance of static properties in AS2
by ericlin


Question: 

I created a custom class extending Math class,

class Math2 extends Math {
    static function arc(r){
        return 2*PI*r;
    }
}

in the fla

trace(Math2.PI); //undefined
trace(Math2.arc(5)); //31.4159265358979

Why is the result ?

1. If static property is inherited, how come Math2.PI is undefined ? 
2. If Math2.PI is undefined, how come Math2.arc calculates correctly ?


Flash MX 2004 starts the AS2 thing. Classes are written by AS2 in a file with new keywords as "public" and "static". Inheritance is supported.

The kernel of Flash is not upgraded so much as we might expected. The actions and tags in SWF format v6 are nearly not changed for v7. We know that, those AS2 syntax are just translated into AS1 script. The support for AS2 syntax is still achieved through the old AS1 mechanism. This means that, all the OOP inheritance implementation is still achieved through prototype things. We may say it is a "mimick". If we implement OOP superficially, the mimick is very successful. However, you may bump into "weird" things if your background is C, JAVA or PHP.

The old AS1 syntax to declare a Class is awkuard to programmer of C, Java. The new AS2 syntax is much similar and quick to handle for them. However, to fully understand the process of OOP in AS2, we must learn the prototype thing of AS1.

Many shut of their ears and refuse to accept the prototype things. When I tell them what happens behind the scene by AS1 syntax, they just say "Oh, that is old outdated AS1, I am using the new AS2". 

This article is for programmers who already knows prototype things.

There are two kinds of properties in a Class. One is "instance property" which exists in the prototype object. The other is "function property" which exists in the constructor itself. The former is similar to the "public" properties in a Class and the later is similar to the "static" properties of a Class.

For public properties, Flash establishes an inheritance chain through prototype. There are already full discussions about the un-necessity and side effect of creating an instance of superClass to serve as prototype object. I am not going to discuss this any more. For static properties, that is not the case.

This discussion is focused on static properties.

In summary, the new compiler achieves the inheritance of static property by modifying our script, hard-coding the name of superClass to replace our subClass to access the property of static properties rather than establishing an inheritance chain.


The translation from AS2 to AS1

Example 1:

class myPack.ClassA {
    static var pp="Hello world"; 
    static function showA_P(){
        trace(pp);
    }
}

The class object (constructor) is created as _global.myPack.ClassA;

The second line "static var pp="Hello world"; is translated as myPack.ClassA.pp="Hello world"; The third line declares a static function and is translated to "myPack.ClassA.showA_P=function(){";This conforms with what we expect. Now, lets check the fourth line. 

How does the method "showA_P" access the value of "pp" ? 

When the compiler meets "pp", it gets to decide it an instance property or a constructor property. If compiler can not resolve this, it displays error message telling that it does not know what "pp" is. 

This is not always a simple job. In this simple, we know easily that "pp" is a static property of present class. However, when we are dealing with some subclass, it needs to search all the inheritance chain. The property "pp" may be just a property of it superClass or super-superClass. It gets to search all the inheritance chain until "pp" is found or not. The job must be resolved during compilation time.

In this example, the compiler scans the properties in this class file, and if "pp" is an instance property (public), then it compiles it to "trace(this.pp);". If it finds out "pp" to be a static property, then it is compiled to "trace(myPack.ClassA.pp);"; Here it is the later.


The inheritance in subClass

Lets start to test a sub-class.

import myPack.ClassA;

class myPack.ClassB extends ClassA {
    static function showB_P(){
        trace(pp);
        trace(myPack.ClassB.pp);
    }
}

ClassB is a subclass of ClassA. 

Our new function "showB_P" tries to access a property "pp" which does not exist in this ClassB. 

Theoretically, "pp" exists in superClass, so it should be accessible through inheritance. How does it achieve this ?

Establish a __proto__ chain might have solved this inheritance problem easily. But, Flash adopts a more complex way.

First, the compiler search in ClassB for the property "pp". If not found, it search through the inheritance chain. It found the taget to be a static property in the superClass and resolved it as "myPack.ClassA.pp". So, what this code really wants to do is to get the value of "pp" in myPack.ClassA. Compiler modify our scripts "trace(pp);" into "trace(myPack.ClassA.pp);" It hard-codes the superClass in the script.

Similar modification happens to the second line. When it try to search "myPack.ClassB.pp", it fails and it just find the property through inheritance chain to resolve it in ClassA, and the script is modified into "myPack.ClassA.pp".

You can check it in the SWF by any decompiler. It is hard-coded as "myPack.ClassA.pp". The whole script is compiled as something like:

myPack.ClassB.showB_P=function(){
    trace(myPack.
ClassA.pp);
    trace(myPack.
ClassA.pp); 
}

Here is our conclusions:

For public property, Flash establish a prototype chain. Inherited properties are accessed through the prototype chain to its superClass and super super Class. For static properties, Flash just "modify" our script and hard-coded the superClass containing that static property into our script. Please note that, nothing about "inheritance chain" gets established for static properties.

The phylosophy is that, 

since the end result is just to displaying out the static property in superClass, why not just access the superClass directly ?!

I put emphasis again: Compiler modify our script to access the superClass. No inheritance chain is established for static properties.

You will not be able to find "myPack.ClassB.pp" in the compiled SWF. Such script does not exist. And, you see that, since there is no inheritance chain, there will be no way to find the non-existing "myPack.ClassB.pp". In other word, if we bypass the compiler, we can never access "myPack.ClassB.pp". There is no "pp" in myPack.ClassB.";


in fla, Acessing a static property in superClass

OK, lets start the even confused implementation about accessing the static property in fla:

import myPack.*;

ClassB.showA_P();
trace(ClassB.pp);

Nothing happens. There is no such method "showA_P" in ClassB. And, there is no such property "pp" in the ClassB. ClassB.pp is undefined.

No inheritance ?! Theoretically, ClassB is a subclass of ClassA. ClassB should be capable of accessing the methods and properties in superClass. Then why that script does nothing ?

Is it because ClassA is not compiled in the SWF ? Check SWF, we see that, ClassA is included well in the SWF. 

Is it because ClassA is not loaded yet ? Check debug, we see that ClassA is loaded without problems. 

Then what ?

Remember what we discussed in the previous section ? Flash does not establish inheritance chain for static properties and methods. Since ClassB does not have "showA_P" method nor a static property "pp", the result should not be surprised.

So, Flash does not support inheritance of static methods ? 

Well, the question should be rephrased as:

Why compiler does not modify our script, change the property owner to super-class as discussed in the previous section ?


Notify the compiler about super Class

Lets add something to make it work

import myPack.*;

ClassA;
ClassB.showA_P();
trace(ClassB.pp);

Hurhey ! It works now.

We add a "junk" code mentioning about "ClassA;" but does nothing. Becareful, do not click "autoformat". Autoformating will remove that "junk" codes.

Why it works now ? Is it because we load ClassA ? NO, we did not load ClassA ! We just mentioned about "ClassA;" That codes does not do any action.

If that junk codes does nothing, what will that "mentioning" affects ? The answer is : it does not affects the player but it affects the compiler.

Because of the mentioning, the compiler modify our script into:

myPack.ClassA.showA_P();
trace(myPack.ClassA.pp);

Compiler changes and modifies our scripts ! It replace our ClassB with ClassA ! Believe me or not. You can check the SWF.

Now it works. The non-working script is modified by the compiler into a working one.

What if the inheritance chain is long ? If we have a ClassC extends ClassB, and we want to trace(ClassC.pp), then we need to mention both ClassB and ClassA to make the compiler modify our script to ClassA.pp;


Lets go back to the question in our Math2 class.

In the Math2 class file, the compiler modify the script and hard-code the superClass into the script. The function "arc" is modified. The script is changed to " return(2*Math.PI*r);" The superClass "Math" gets hard-coded in. That is why this function does well by itself. It works anytime , anywhere when we call it  Math2.arc(r);

For the Math2.PI property, unless compiler modifies our script, there is nothing named as PI in class Math2. To trace(Math2.PI) will output undefined. 

How to make it work ? How to make compiler modify our script ? You should have figured out my answer: just mention the superClass before we access the static properties.

Math;
trace(Math2.PI); //3.14159265358979
trace(Math2.arc(5)); //31.4159265358979

This forces compiler to modify our script. The first trace script is modified to "trace(Math.PI);" and it outputs 3.14159.


To mention or not to mention is the problem. 

Check the examples below.

trace(Math2.PI);  // output undefined
trace(Math.abs(1)); // output 1
trace(Math2.PI); //output 3.14159

The first line fails, but the third line succeeds. It is because we "mentioned" Math class in the second line. That affects the compilation process for scripts in this block after this line.

Do you know what codes are finally compiled into the SWF ? Here they are:

trace (Math2.PI);
trace (1);
trace (Math.PI);

1.
The first line is compiled as it is. That is why it outputs "undefined".

2. 
The second line is compiled with pre-compiling evaluation. The result of "Math.abs(1)" is calculated to be 1 and the value is compiled directly into the code. The end code turns out to be "trace(1);". Such pre-compiling evaluatioin simplify the script and helps to improve the run-time performance efficiency.

Please note that, after compilation, the code does not evoke the Math object any more.  

3. 
The third line is modified by the compiler. The "Math2" is changed to "Math" because the compiler meets "Math" in the second line during compilation. Now, the script outputs the PI value successfully on test movie.


Why not establish an inheritance chain ?

The reason why Flash modifies the script rather than establishing an inheritance chain is mysterious to me. The only reason I can guess is the "pre-compiling evaluation". Macromedia might believe that, directly coding the target is more efficient than dynamically searching the target through inheritance chain during run-time. 

If I need to "mention" the superClass only once in the fla, I would accept that policy. However, compilation is done per script block. "Mentioning" the superClass repeatedly in each script block when we need to access an inherited  static property is non-sense. 

If you download a compiled package, how do you know the inheritance chain ?

Compiler is not truthful. It would easily missed some dynamic naming syntax. 

A syntax such as "trace(ClassB["p+p"]);" will be lost by the compiler. 

To establish inheritance chain is very very easy through __proto__ chain. Why not do it ?

class Math2 extends Math {
    static var __proto__=Math;
    static function arc(r){
        return 2*PI*r;
    }
}

trace(Math2.PI); //3.14159265358979
trace(Math2.arc(5)); //31.4159265358979

See how it works ?! If compiler could add __proto__ for us, so that I dont need to script that ugly __proto__ in the class file ?! Is'nt that a better solution ?


ericlin@ms1.hinet.net