Introduction
Objects
Instances
Local
Inheritance
Prototypes
Override
Overwrite
Protection
Arguments
Constructors
Methods
Proto
Arguments Array
Callee
New
Extend
Super
Glossary
 
 
Debreuil Digital Works © 2001
 

Super - The Running of the Constructors

After the extends function, running the constructors should be a walk in the park on a sunny day. We essentially must do two things. Pass arguments up to the constructors that need them, and then run the constructors from top down. The only thing that makes this tricky is that the constructors are not naturally related to each other like the prototypes are. So what we must do is climb the prototype chain, and at each level, jump back to the constructor.

Once again, it helps to look to other OO languages to see how they go about this. Java uses a keyword called 'super', which does exactly what we are wanting, plus a little - so it merits a closer look. In Java, the 'super' keyword is used to call the parent class's constructor, with arguments if desired, using the syntax super(arg0, arg1, ...). The restriction is that it must be the very first line in every constructor unless omitted, in which case it will be automatically inserted without arguments. Instead of deleting itself when it is finished running the constructors, it gets a second shot at life in the form of a pointer to the parent class. This allows instances to invoke overridden methods by saying super.xxx( ).

The good news is we can have all that Java's 'super' has, in a custom Actionscript routine - if we are willing to place two small burdens on the user (and remember, when the user feels pain, we feel nothing). Burden number one is that they will have to say this.super( ) rather than just super( ). Instances love the word 'this' when they are talking about themselves, and looking over a typical program, they do seem to love talking about themselves (as Oscar Wilde once said, "but enough about me, what do you think of me?"). In this case they are talking about their own super routine, so that would be this.super, no easy way around it. This is a feature - if not for 'this', our Actionscript 'super' routine would be so similar to Java's 'super' that people might forgetfully try to pass off bouncing heads as animation.

The second burden, is that the user MUST have this.super( ... ) as the first line in every constructor. Well, we aren't magic, but there are ways to check if a constructor has a 'super' call or not, and insert one if needed. Unfortunatly all of these involve running the constructor, which may skew things like a static variable that keeps track of how many instances have been created. So we'll "make the user pay!", and demand that they put 'this.super( )' as the first line of every constructor. Will it throw an error if they don't (like Java does)? Well, not right off the bat, he he. You have to be a heartless bastard to write general purpose libraries in Actionscript, never forget that.

So here is the routine. It passes the arguments up the constructor chain, and then runs the constructors in order from top down. Once it is done, it changes 'super' to mean parent.prototype, like Java does - so you can access an overridden property or method by saying this.super.xxx( ). See if you can follow it. (I almost can, but then again, I wrote it!). TODO: explain this a wee bit better ; ).


// SUPER ----------------------
Object.customKeyword.prototype.super = function()
{
    // this.super(); must be the first line in every constructor
 
    // get chain counter - tells us how many times super
    // has been called since new instance created (as it 
    // climbs up the constructor chain). This also increments
    // the counter.
    var count   = Object.customKeyword.prototype.super.prototype.cnt++;

    // find the next constructor to run
    var fn = this.__proto__.__proto__;
    while(count-- > 0)
    {
        fn = fn.__proto__;
    }
    fn = fn.constructor;

    // run that constructor into the instance, passing args
    this.$_base = fn;
    this.$_base(  arguments[0],arguments[1],
                  arguments[2],arguments[3],
                  arguments[4],arguments[5],
                  arguments[6],arguments[7] );
    delete this.$_base;
    
    // check to see if we are at top of chain
    if(fn.prototype.__proto__ == Object.customKeyword.prototype)
    {
        // if so, override the meaning of super for this instance
        // now super points to parent's prototype
        // so it's overloaded functions can be called, 
        // and it's overloaded parent args retreived
        this.super = this.__proto__.__proto__.prototype;
        // reset the chain counter to zero for next instance
        Object.customKeyword.prototype.super.prototype.cnt = 0;
    }
}
Object.customKeyword.prototype.super.prototype.cnt  = 0;
		

 

Extend < < Home > > Custom