Changeset 17

Show
Ignore:
Timestamp:
11/14/05 18:34:02 (3 years ago)
Author:
Jan-Klaas Kollhof
Message:

new class setup handling to allow better multi inheritance and generation of callable objects

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • jsolait/trunk/jsolait/jsolait.js

    r16 r17  
    3535                                            If the created class is a public member of a module then  
    3636                                            the __name__ property of that class is automatically set by Module(). 
    37     @param superClass=Object    The class to inherit from (super class). 
    38     @param mixinClass(*)           The mixin classes. 
     37    @param bases *                  The base classes. 
    3938    @param classScope(-1)        A function which is executed for class construction. 
    4039                                            As 1st parameter it will get the new class' protptype for  
     
    4241                                            the super class' wrapper for calling inherited methods. 
    4342**/ 
    44 Class=function(name, superClass, mixinClass, classScope){ 
     43Class=function(name, bases, classScope){ 
    4544    var args=[]; 
    4645    for(var i=0;i<arguments.length;i++){ 
     
    5655        name="anonymous"; 
    5756    } 
    58     //the next arg should be the superclass 
    59     if(args.length > 0){ 
    60         superClass = args.shift(); 
     57    //the rest of the arguments should be base classses 
     58    var bases = args; 
     59     
     60    //set up the 'public static' fields of the class 
     61    var statc={__isArray__ : false, 
     62                     __name__ : name, 
     63                     __bases__: bases, 
     64                     __hashCount__:0, 
     65                     __str__ : function(){ 
     66                            return "[class %s]".format(this.__name__); 
     67                        } 
     68                    }; 
     69 
     70    var baseProtos=[];//stores the prototypes of all the base classes 
     71    var proto; //the prototype to use for the new class 
     72    if(bases.length==0){//use Object as base 
     73        proto={}; 
     74        proto.__str__ = function(){ 
     75            return "[%s %s]".format(this.__class__.prototype.__call__ === undefined ? 'object' : 'callable', this.__class__.__name__); 
     76        }; 
     77        //because toString is not apearing in a for in loop we will just use __str__ and always assign it to toString 
     78        //this makes prototype creatin a bit simpler 
     79        proto.toString=proto.__str__; 
     80        statc.__bases__=[Object]; 
     81    }else{ //inherit from all base classes 
     82        //inheritance is done by  
     83        var baseProto; 
     84        for(var i=0;i<bases.length;i++){ 
     85            var baseClass = bases[i]; 
     86            //remember the base prototypes 
     87            baseProtos.push(baseClass.prototype); 
     88            if(baseClass.__proto__ !== undefined){ 
     89                baseProto = baseClass.__proto__(); 
     90            }else{ 
     91                baseProto = new baseClass(Class); 
     92            } 
     93            statc.__isArray__ = statc.__isArray__ || baseClass.__isArray__; 
     94             
     95            if(i==0){//for the first base class just use it's proto as the final proto 
     96                proto = baseProto; 
     97            }else{//for all others extend(do not override) the final proto with the properties in the baseProto 
     98                for(var key in baseProto){ 
     99                    if(proto[key] === undefined){ 
     100                        proto[key] = baseProto[key]; 
     101                    } 
     102                } 
     103            } 
     104            //extend the new class' static interface 
     105            for(var key in baseClass){ 
     106                if(statc[key] === undefined){ 
     107                    statc[key] = baseClass[key]; 
     108                } 
     109            } 
     110        } 
     111        //make sure the toString points to __str__, this will make overwriting __str__ after object construction impossible (todo ?)  
     112        //but will be faster than having toString call __str__, also overwriting methods unless they are ment to be overridden is not cool anyways. 
     113        proto.toString=proto.__str__; 
     114    } 
     115    //make sure all jsolait objects have a hash method 
     116    if(proto.__hash__ === undefined){ 
     117        proto.__hash__=function(){ 
     118            if(this.__id__ === undefined){ 
     119                this.__id__ = Class.__hashCount__++; 
     120            } 
     121            return this.__id__; 
     122        }; 
     123    } 
     124         
     125    //todo: run the class scope as scope(publ, [statc,] baseClassProto1, ... )  
     126    //publ represents the new class' prototype, statc the public static fields of the class(class properties) 
     127    if(classScope.length>baseProtos.length+1){ 
     128        classScope.apply(this,[proto,statc].concat(baseProtos)); 
    61129    }else{ 
    62         superClass = Object
     130        classScope.apply(this,[proto].concat(baseProtos))
    63131    } 
    64     var mixinClasses=args; 
    65      
    66     //this is the constructor for the new objects created from the new class. 
    67     //if and only if it is NOT used for prototyping/subclassing the __init__ method of the newly created object will be called. 
    68 //todo: this breaks mozilla's implementation of instanceof which returns true for every jsolait object and any jsolait class 
    69 //a workaround would be using new Function     
    70     var NewClass = function(calledBy){ 
    71         if(calledBy !== Class){ 
    72             //simulate Array and Function subclassing 
    73             if(NewClass.prototype instanceof Array || NewClass.prototype instanceof Function){ 
    74                 var rslt; 
    75                 if(NewClass.prototype instanceof Array){ 
    76                     rslt=[]; 
    77                 }else{ 
    78                     rslt = function(){ 
    79                         return rslt.__call__.apply(rslt, arguments); 
    80                     }; 
    81                 } 
    82                 //transfer all properties defined in teh class to the new object(as it is empty) 
    83                 for(var n in NewClass.prototype){ 
    84                     rslt[n] = NewClass.prototype[n]; 
    85                 } 
    86                 //these props are not copied in the above loop 
    87                 rslt.constructor = NewClass; 
    88                 rslt.toString = NewClass.prototype.toString; 
    89                      
    90                 rslt.__init__.apply(rslt,arguments); 
     132         
     133    //allthough a single constructor would suffice for generating normal objects, Arrays and callables, 
     134    //we use 3 different ones. This will minimize the code inside the constructor and therefore 
     135    //minimize object construction time 
     136    if(proto.__call__){ 
     137        //if the callable interface is implemented we need a class constructor  
     138        //which generates a function upon construction 
     139        var NewClass = function(calledBy){ 
     140            if(calledBy !== Class){ 
     141                var rslt = function(){ 
     142                    return rslt.__call__.apply(rslt, arguments); 
     143                }; 
     144                var proto=arguments.callee.prototype; 
     145                for(var n in proto){ 
     146                    rslt[n] = proto[n]; 
     147                } 
     148                rslt.constructor = arguments.callee; 
     149                rslt.toString = proto.__str__; 
     150                if(rslt.__init__){ 
     151                    rslt.__init__.apply(rslt, arguments); 
     152                } 
    91153                return rslt; 
    92             }else{ 
    93                 //todo should a constructor be able to return something? 
    94                 this.__init__.apply(this, arguments); 
    95             } 
    96         } 
    97     }; 
    98     //This will create a new prototype object of the new class. 
    99     NewClass.__createProto__ = function(){ 
    100         return new NewClass(Class); 
    101     }; 
    102     //setting class properties for the new class. 
    103     NewClass.__super__ = superClass; 
    104     NewClass.__name__= name;  
    105     NewClass.toString = function(){ 
    106         return "[class %s]".format(NewClass.__name__); 
    107     }; 
    108      
    109    //see if the super class can create prototypes. (creating an object without calling __init__()) 
    110     if(superClass.__createProto__!==undefined){ 
    111         NewClass.prototype = superClass.__createProto__(); 
    112     }else{//just create an object of the super class 
    113         NewClass.prototype = new superClass(); 
     154            } 
     155        }; 
     156    }else if(statc.__isArray__){ 
     157        //Since we cannot inherit from Array directly we take the same approach as with the callable above 
     158        //and just have a constructor which creates an Array  
     159        var NewClass = function(calledBy){ 
     160            if(calledBy !== Class){ 
     161                rslt=[]; 
     162                var proto=arguments.callee.prototype; 
     163                for(var n in proto){ 
     164                    rslt[n] = proto[n]; 
     165                } 
     166                rslt.constructor = proto; 
     167                rslt.toString = proto.__str__; 
     168                if(rslt.__init__){ 
     169                    rslt.__init__.apply(rslt, arguments); 
     170                }else{//implement Array's defaul behavior 
     171                    if(arguments.lengt==1){ 
     172                        rslt.length=arguments[0]; 
     173                    }else{ 
     174                        for(var i=0;i<arguments.length;i++){ 
     175                            rslt.push(arguments[i]); 
     176                        } 
     177                    } 
     178                } 
     179                return rslt; 
     180            } 
     181        }; 
     182    }else{ 
     183        //this is a 'normal' object constructor which does nothing but call the __init__ method  
     184        //unless it does not exsit or the constructor was used for prototyping 
     185        var NewClass = function(calledBy){ 
     186            if(calledBy !== Class){ 
     187                if(this.__init__){ 
     188                    this.__init__.apply(this, arguments); 
     189                }     
     190            } 
     191        }; 
    114192    } 
     193     
    115194    //reset the constructor for new objects to the actual constructor. 
    116     NewClass.prototype.constructor = NewClass; 
    117      
    118      
    119     //make sure the new class has an __init__ method if it inherits from Object, Array or Function 
    120     switch(superClass){ 
    121         case Object: 
    122             NewClass.prototype.__init__=function(){};     
    123             NewClass.prototype.toString = function(){ 
    124                 return "[object %s]".format(this.constructor.__name__); 
    125             }; 
    126             //todo 
    127             NewClass.prototype.__hash__=function(){ 
    128                 if(this.__id__==null){ 
    129                     this.__id__ = '#auto#' +  (Class.hashCount++); 
    130                 } 
    131                 return this.__id__; 
    132             }; 
    133             break; 
    134         case Array: 
    135             //immitate a call to new Array() 
    136             NewClass.prototype.__init__=function(){ 
    137                 if (arguments.length==0){ 
    138                 }else if(arguments.lengt==1){ 
    139                     this.length=arguments[0]; 
    140                 }else{ 
    141                     for(var i=0;i<arguments.length;i++){ 
    142                         this.push(arguments[i]); 
    143                     } 
    144                 } 
    145             };     
    146             break; 
    147         case Function: 
    148             //Subclasses of Function do not impl. Function's default behavior 
    149             //as this would not make much sense, we allow subclassing of functions so people can create callable objects 
    150             NewClass.prototype.__init__=function(){}; 
    151             //needs to be overwritten by users 
    152             NewClass.prototype.__call__=function(){}; 
    153             NewClass.prototype.toString=function(){ 
    154                 return "[callable %s]".format(this.constructor.__name__); 
    155                 //todo: return Function.prototype.toString.call(this); 
    156             }; 
    157             break; 
     195    proto.constructor = NewClass; 
     196    proto.__class__= NewClass;//no, it is not needed, just like __str__ is not, but it is nicer than constructor 
     197     
     198    //this is where the inheritance realy happens 
     199    NewClass.prototype = proto; 
     200     
     201    //apply all the static fileds 
     202    for(var key in statc){ 
     203        NewClass[key] = statc[key]; 
    158204    } 
    159      
    160     //mixin classes overwrite props/methods of the new class 
    161     for(var i=0;i<mixinClasses.length;i++){ 
    162         var mixin = mixinClasses[i].prototype; 
    163         for(var n in mixin){ 
    164             if(n != "__init__"){ 
    165                 NewClass.prototype[n] = mixin[n]; 
    166             } 
    167         } 
    168     } 
    169      
    170     //execute the scope of the class 
    171     switch(classScope.length){ 
    172         case 3: //publ, statc, supr   
    173             classScope(NewClass.prototype, NewClass, superClass.prototype); 
    174             break; 
    175         default://publ, supr 
    176             classScope(NewClass.prototype, superClass.prototype); 
    177             break; 
    178     } 
     205    NewClass.toString=statc.__str__; 
    179206     
    180207    return NewClass; 
    181208};     
    182 Class.hashCount=0; 
     209Class.__hashCount__=0; 
     210 
    183211Class.toString = function(){ 
    184212    return "[object Class]"; 
    185213}; 
    186214 
    187 Class.__createProto__=function(){  
    188     throw "Can't use Class as a super class."; 
     215Class.__proto__=function(){  
     216    throw "Can't use Class as a base class."; 
    189217}; 
     218 
     219Array.__isArray__=true; 
     220Array.__str__=Array.toString=function(){return "[class Array]";}; 
     221Array.__proto__=function(){ var r =[]; r.__str__ = Array.prototype.toString;  return r; }; 
     222Object.__str__=Object.toString=function(){return "[class Object]";}; 
     223Function.__proto__ = function(){ throw "Cannot inherit from Function. implement the callabel interface instead using YourClass::__call__.";}; 
     224 
    190225 
    191226 
     
    235270}; 
    236271 
    237 Module.__createProto__=function(){  
    238     throw "Can't use Module as a super class."; 
     272Module.__proto__=function(){  
     273    throw "Can't use Module as a base class."; 
    239274}; 
    240275 
     
    258293     
    259294     
    260     publ.toString=function(){ 
     295    publ.__str__=function(){ 
    261296        var s = "%s %s".format(this.name, this.module); 
    262297        return s; 
     
    764799        var a=new Array(l+1); 
    765800        return a.join(this); 
    766     } 
     801    }; 
    767802     
    768803    ///Tests the module. 
  • jsolait/trunk/jsolait/lib/iter.js

    r13 r17  
    9292            } 
    9393        }; 
     94         
    9495    }); 
    9596     
     
    158159        Iteration class for handling iteration steps and callbacks. 
    159160    */ 
    160     mod.Iteration = Class(function(publ, supr){ 
     161    mod.Iteration = Class(function(publ,supr){ 
    161162        /** 
    162163            Initializes an Iteration object. 
     
    299300     
    300301    mod.__main__=function(){ 
     302         
     303         
    301304        var  testing = imprt('testing'); 
    302305        var task=function(){ 
     
    311314            r[i] = i; 
    312315        } 
    313          
     316                        
    314317        print("for loop \t\t\t" + testing.timeExec(100,function(){ 
    315318            var s=''; 
  • jsolait/trunk/jsolait/lib/jsonrpc.js

    r8 r17  
    125125        The results and errors are passed to the callback. 
    126126    */ 
    127     mod.JSONRPCMethod =Class(Function, function(publ){ 
     127    mod.JSONRPCMethod =Class(function(publ){ 
    128128         
    129129        var postData = function(url, user, pass, data, callback){ 
  • jsolait/trunk/jsolait/lib/sets.js

    r13 r17  
    9191            var h; 
    9292            if(item.__hash__){ 
    93                 h='#' +item.__hash__(); 
     93                h='@' +item.__hash__(); 
    9494            }else{ 
    9595                h='#' +item; 
     
    110110            var h; 
    111111            if(item.__hash__){ 
    112                 h='#' +item.__hash__(); 
     112                h='@' +item.__hash__(); 
    113113            }else{ 
    114114                h='#' +item; 
     
    131131            var h; 
    132132            if(item.__hash__){ 
    133                 h='#' +item.__hash__(); 
     133                h='@' +item.__hash__(); 
    134134            }else{ 
    135135                h='#' +item; 
     
    148148            var h; 
    149149            if(item.__hash__){ 
    150                 h='#' +item.__hash__(); 
     150                h='@' +item.__hash__(); 
    151151            }else{ 
    152152                h='#' +item; 
  • jsolait/trunk/jsolait/lib/xmlrpc.js

    r8 r17  
    503503        The results and errors are passed to the callback. 
    504504    */ 
    505     mod.XMLRPCMethod =Class(Function, function(publ){ 
     505    mod.XMLRPCMethod =Class(function(publ){ 
    506506        var postData = function(url, user, pass, data, callback){ 
    507507            if(callback == null){