Hok's Macromedia Flash Blog

macromedia flash actionscript scripting, php, remoting, webservices, c#, javascript

Inheritance: addClass revised

After i have found the failure of our addClass-method,
i took a deep watch to the proto-chain, constructor,
__constructor__ things.

Well, in the first moment my picture was off a big
anaconda-snake which i had to wrestle to become
sir of the situation, but a few traces later i got back
the controll over the situation.




Hence, i have the method-complete. And i think it
realy cool tool for inheritance.

Till now i have found the following Advantages and
Disadvantages:

Disadvantages


  • Not Macromedia recommended inheritance-way, but
    it does nothing more than using the proto-way of inheritance.

  • It is possible that other programmers do not see that
    an object have inherited, so more conventions and/or comments are
    needed.


Advantages

  • Object.registerClass allowes that you associate only one MC with
    one Element in the Libary. With the addClass-method it is possible to
    attach the clip and than set the class.

  • It is easy possible to attach a class to an existing mc.

  • It is possible to add unlimented classes to an object.

  • You can dynamicly add classes to your Objects. So it very
    comfortable to construct factorys, which have in their hand to
    controll the specialisation of the generated objects.


Please tell me what you think, did you see more pros and cons?
if (Object.prototype.addClass != undefined) {
   trace('ERROR: Method with the name Object.prototype.addClass is allready defined!');
}
Object.prototype.addClass = function (pConstructor) {
   //
   // Adds a class to an existing as-obj or mc-obj.
   //
   // The added class will be interjected to the
   // beginning of the objects proto-chain.
   // The super-operator works than in the new
   // chain-order.
   // The class to add can be specialized(inherited).
   //
   // Tests i have done:
   // - Multiple inheterence
   // - multiple call of addClass
   // - using with mcs
   // - using with mcs which was Object.registerClassed
   // - Allways i taked a deep watch to the generated
   //  proto-chain and allways compared to the proto-chain
   //  that comes out by standard inheritance and i have
   //  found no difference. So polimorphy works still fine.
   //
   // Untested
   // - it should also no problem to add an Class
   //  to a prototype.__proto__ for the multiple
   //  extending of a Class
   //
   var tmp = this.__proto__;
   this.__proto__ = pConstructor.prototype;
   var pp, p = this.__proto__;
   while (pp = p.__proto__) {
      if (pp == Object.prototype || pp == MovieClip.prototype) {
        p.__proto__ = tmp;
        p.constructor = this.constructor;
        p.__constructor__ = (tmp == MovieClip.prototype) ? MovieClip : this.__constructor__;
        this.constructor = pConstructor;
        this.__constructor__ = pConstructor;
        return true;
      } else {
        p = pp;
      }
   }
   return false;
}

Posted by hOk at April 30, 2003 04:57 PM

Avoiding-Bugs: Extension of built-in-prototypes

I have just thought about possible side-effects
that can occur if we use an prototype-extension
with the same name twice. Uhh, that could be
horrible especially for teamwork, so that everyone
have to know exactly what extensions the other
did.
A really simple solution is to check wether that
extension exist before we define the extension, if so
we can throw an error otherwise our trace-window
stay nice and clean...;-)
if (Object.prototype.addClass != undefined) {
   trace('ERROR: Object.prototype.addClass exist allready!');
}
Object.prototype.addClass = function (pConstructor) {
   // Adds a class to an object, to the
   // beginning of the proto-chain.
   var tmp = this.__proto__;
   this.__proto__ = pConstructor.prototype;
   this.__proto__.__proto__ = tmp;
}
ASSetPropFlags(Object.prototype, null, 1, 0);

So we can stay concentrate on the real importent
things in our programms.

The little philosophy behind this test is the self-testing-code
philosophy. That means that we only get a message if an
error happens and we did not have to evaluate trace window
for inconsistencies by our self.

Posted by hOk at April 29, 2003 03:12 PM

Constructor-Factory

Here is a way to use the constructor of an abstract-class
as factory:




Object.prototype.addClass = function (pConstructor) {
   // Adds a class to an object, to the
   // beginning of the proto-chain.
   var tmp = this.__proto__;
   this.__proto__ = pConstructor.prototype;
   this.__proto__.__proto__ = tmp;
}
ASSetPropFlags(Object.prototype, null, 1, 0);

// Abstract-Factory-Constructor
AbstractCarClass = function (pConcreteClass) {
   // default-properties
   this.intMaxSpeed = 130;
   this.intPrice = 15000;
   //
   this.addClass(pConcreteClass);
   this.init();
}
AbstractCarClass.prototype.changeClass = function (pConcreteClass, pBlnInitialize) {
   this.__proto__ = pConcreteClass.prototype;
   if (pBlnInitialize) this.init();
}
AbstractCarClass.prototype.init = function () {
   //
   // Should be overwritten in concrete-class to
   // initialize properties.
   //
}
// concrete-class
PorscheClass = function () {}
PorscheClass.prototype.init = function () {
   this.intMaxSpeed = 240;
   this.intPrice = 70000;
}
PorscheClass.prototype.toString = function () {
   return '[object PorscheClass]';
}
// concrete-class
LanciaClass = function () {}
PorscheClass.prototype.init = function () {
   this.intMaxSpeed = 120;
   this.intPrice = 10000;
}
LanciaClass.prototype.toString = function () {
   return '[object LanciaClass]';
}
// test
objCar = new AbstractCarClass(PorscheClass);
trace(objCar); // [object PorscheClass]
//
objCar.changeClass(LanciaClass, true);
trace(objCar); // [object LanciaClass]

Posted by hOk at April 27, 2003 04:49 PM

Scite|Flash: Own methods for the Scite|Flash-flash.api-file

I have written a little vbs, that extracts methods from
your as-files into a getMethodsResult.txt-file.
Each line in the result-file have the following format:
methodName(param1, param2[,...]) // className
If you put the result-text in the flash.api-file from
the Scite|Flash-Editor you get autocomplete and
hints for your methods.
You simply have to run the getMethods.vbs
in the directory where your as-files are.

Posted by hOk at April 26, 2003 11:50 AM

MovieClip-Broadcaster

Sometimes you need a typecally movieclip-event-source,
here is a MovieClip-Extension wich adds broadcasters for
for the EnterFrame-, MouseMove-, MouseUp- and MouseDown-Event.

initMovieClipBroadcasters = function () { _level0.createEmptyMovieClip('mcEventSource', 1000000); var arrBroadcaster = ['EnterFrame','MouseMove','MouseUp','MouseDown']; for (var i = 0; i < arrBroadcaster.length; i++) {  var strBcName = 'bc' + arrBroadcaster[i];  var strEventName = 'on' + arrBroadcaster[i];  var objBroadcaster = MovieClip[strBcName] = new Object();  ASBroadcaster.initialize(objBroadcaster);  objBroadcaster.strEventName = strEventName;  objBroadcaster.$oldAddListener = objBroadcaster.addListener;  objBroadcaster.$oldRemoveListener = objBroadcaster.removeListener;  objBroadcaster.addListener = function (pObjListener) {   this.$oldAddListener(pObjListener);   var objBroadcaster = this;   var strEventName = this.strEventName;   _level0.mcEventSource[strEventName] = function () {    objBroadcaster.broadcastMessage(strEventName);   }  }  objBroadcaster.removeListener = function (pObjListener) {   this.$oldRemoveListener(pObjListener);   if (this._listeners.length == 0) {    _level0.mcEventSource[this.strEventName] = null;   }  } }}initMovieClipBroadcasters();delete initMovieClipBroadcasters;// Example:obj = new Object();MovieClip.bcEnterFrame.addListener(obj);MovieClip.bcMouseUp.addListener(obj);//MovieClip.bcEnterFrame.removeListener(obj);obj.onEnterFrame = function () { trace('onEnterFrame'); }obj.onMouseUp = function () { trace('onMouseUp'); }

Posted by hOk at April 18, 2003 01:49 PM

Two Points to use the toString-method in classes

The toString-method is rarly used. But it is a good practice,
because it helps to understand youre code, example:
// Example 1(without toString)Car = function (pHexColor) { this.hexColor = pHexColor;}objAudi = new Car();trace(objAudi); // output: [object Object]// Example 2(with toString)Car = function (pHexColor) { this.hexColor = pHexColor;}Car.prototype.toString = function () { return '[object Car]';}objAudi = new Car();trace(objAudi); // output: [object Car] So the difference is the Information we get
while tracing an object.
But toString can also be interesting for
so called hashes(in AS also called value-objects)
but first we need to modify our class a little bit:
// Example 3Car = function (pHexColor) { // unique-id this.intId = ++arguments.callee.intGeneratedObjects; this.hexColor = pHexColor;}// class-property or static-propertyCar.intGeneratedObjects = 0;Car.prototype.strClassName = 'Car';Car.prototype.toString = function () { return '[object '+this.strClassName+this.intId+']';}objAudi = new Car();trace(objAudi); // output: [object Car1] Now lets see how easy it is to store our object in
hash-table: // create the listener-hashhashListeners = new Object();// store our object as listenerhashListeners[objAudi] = objAudi;// delete our object from the listener-hashdelete hashListeners[objAudi]; OK, that was not really a big deal,
regards, Holger...:-)

Posted by hOk at April 17, 2003 12:52 PM

Debugging: setFunctionNames

Sometimes it is important to know what function exactly
calls a function or a method. Making use of the function
above you can simply determine the caller by tracing the
'arguments.caller.name' within a function.
setFunctionNames = function (pObjContainer) {
   // Description:
   // Sets the property "name" for every Function
   // that was found in "pObjContainer"
   // Arguments:
   // pObjContainer -> Obj|Mc in which to rekusivly
   //      search for functions
   pObjContainer = pObjContainer || _root;
   for (var p in pObjContainer) {
      if (typeof pObjContainer[p] == 'object') {
        arguments.callee(pObjContainer[p]);
      } else if (typeof pObjContainer[p] == 'function') {
        pObjContainer[p].name = p; // <-- sets the name
        arguments.callee(pObjContainer[p].prototype);
      }
   }
}

Posted by hOk at April 7, 2003 04:29 PM

Performance: fastest while-loop for traversing an array

There was a discussion on flashcoders-mailinglist what the
fastest while-loop is. The result is interessting, it shows the
speed-difference between the minus- and plus-operator
and post- and pre-increment-operator. It seems that the
postincrement ist slower because it have to store the new value
until the rest of the expression is evaluated. c = 40000;t = getTimer();l = c;while (l--);trace(getTimer() - t);t = getTimer();l = c;while (--l+1);trace(getTimer() - t);t = getTimer();l = c;while (--l-(-1));trace(getTimer() - t);// output:// 744// 549// 545

Posted by hOk at April 5, 2003 05:11 PM

Funny Math

I have just found an older thread in ultrashock
math-forum, really cool how many ways possible to
toggle a variable between 1 and 2, hehe: k = 3-kk = (k==1)?2:1;if(!(k--)) k=2;k = (k%=2)+1;k = k%2+1;k = !(k-1) + 1;k = 1 + sin(asin(k-1) + PI/2);k = pow(2,2-k);(k-1)? (k >>= 1) : (k <<= 1);k = (Math.log(k)) ? --k : ++k;k = (((k&1)<<2)|k)>>1;k = (Math.sqrt(--k)) + 2*(!k);k = 1-(k--*--k);k = 1+!(--k/k);k = !(++k%--k)+1;k = (k>>1|k<<1)&3;k = 2/k;k = Math.abs(k*3-5);k = Math.ceil(Math.cos(k))+1;k = Math.round(2.4-k/2);k = 2-Math.floor(Math.tan(--k));k = Math.abs((k^2)-1);

Posted by hOk at April 5, 2003 04:28 PM

Debugging: traceMessages

Sometimes you need to know which methods of an
object called in which order, here is a function that
do this job.




traceMessages = function (pObj, pBlnLastMethodOnly) {
   for (var p in pObj) {
      if (typeof pObj[p] != 'function') continue;
      var tmp = pObj[p];
      pObj[p] = function() {
        var t = getTimer() - arguments.callee.__traceMessages.intLastCallTime;
        arguments.callee.__traceMessages.intLastCallTime = getTimer();
        trace('<call-of ['+t+']> ' + arguments.callee.__methodName + '(' + arguments.join(', ') + ')');
        return arguments.callee.__originalMethod.apply(this, arguments);
      }
      pObj[p].__methodName = p;
      pObj[p].__originalMethod = tmp;
      pObj[p].__traceMessages = arguments.callee;
      if (pBlnLastMethodOnly) return '';
   }
   return '';
}

// example:
// ========
CarClass = function () {
}
CarClass.prototype.init = function () {
   this.turnEngineOn();
}
CarClass.prototype.turnEngineOn = function () {
   trace('brum brum...');
}
objCar = new CarClass();
traceMessages(objCar); // <--
objCar.init();
// output:
// =======
// <call-of [38]> init()
// <call-of [0]> turnEngineOn()
// brum brum...

Posted by hOk at April 4, 2003 01:53 PM

New Place