From: Gavin Kistner Date: 2005-08-17T21:57:10+09:00 Subject: Re: Prototype-based / Ruby question --Apple-Mail-4--52668417 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; delsp=yes; format=flowed On Aug 17, 2005, at 2:21 AM, zimba.tm@gmail.com wrote: > As I understand the definition, prototype based languages don't > instanciate objects from a class, but rather clone an existing model > object. Ruby's classes are objects. From research on the web, it appears that the above definition is the commonly-held one. I had always thought that 'prototype-based' referred to the object-chaining available in languages like Javascript (where the chain uses the word 'prototype') or Lua (the __index metatable property). Is there another term to cover this sort of 'inheritance'? Or is this an important aspect of prototype-based languages for representing inheritance? [Non-Ruby Code Samples Follow] For those who don't know what I'm talking about, the following JavaScript and Lua examples show how you can make simple 'instance' objects have access to a common 'class' object, including changing the methods and properties on that class after instantiation. JavaScript: Mammal = function( ){ this.isAlive = true; } Mammal.prototype.hasHair = true; Mammal.prototype.die = function( ){ this.isAlive = false; } Person = function( inName ){ this.name = inName; } Person.prototype = new Mammal; //other 'best practice' inheritance details omitted for clarity Person.prototype.toString = function(){ return "[Person '"+this.name+"']"; } var gk = new Person( "Gavin Kistner" ); gk.nickname = "Phrogz"; // instance property alert( gk ); // [Person 'Gavin Kistner'] alert( gk.isAlive ); // true alert( gk.hasHair ); // true Person.prototype.eat = function(){ if ( !this.weight ) this.weight = 170; this.weight += 1; } gk.eat( ); alert( gk.weight ); // 171 gk.die( ); alert( gk.isAlive ); // false In the above, when gk.hasHair is referenced, JavaScript looks: * In the gk object for a hasHair property * In the constructor's (Person) prototype object for a hasHair Property * In the constructor's prototype's prototype object for a hasHair Property (where it is found) When the die() method is invoked on gk, it is found on the Mammal prototype, but 'this' is still the gk object. While reading the value of 'isAlive' on gk searches up the prototype chain for that property, setting the value creates a new property on the gk object itself. Lua: Mammal = { isAlive = true, --by default, overridden per instance if needed hasHair = true, die = function( self ) self.isAlive = false end } Person = { new = function( inClass, inName ) local instance = { name = inName } setmetatable( instance, inClass.inheritTable ) return instance end, proto = { -- empty to begin with }, inheritTable = { __tostring = function(self) return "[Person '"..self.name.."']" end } } Person.inheritTable.__index = Person.proto --inherit properties from Mammal setmetatable( Person.proto, { __index = Mammal } ) local gk = Person:new( "Gavin Kistner" ) gk.nickname = "Phrogz" print( gk ) --> [Person 'Gavin Kistner'] print( gk.isAlive ) --> true print( gk.hasHair ) --> true Person.proto.eat = function( self ) if not self.weight then self.weight = 170 end self.weight = self.weight + 1 end gk:eat( ) print( gk.weight ) --> 171 gk:die( ) print( gk.isAlive ) --> false In Lua, every 'table' (hash object) can have another 'metatable' associated with it. While the table holds information about the object itself, the metatable holds information about that object's inheritance chain, string conversion, operator overloading, and more. If Lua cannot find a property for an object in the object's table, it sees if the object has a metatable with an __index property pointing to another table; if so, it asks that table for the value. Like the JS example, the Lua above has three main objects - the gk table, the Person.proto table, and the Mammal table. (The Person table itself is a nice namespace wrapper for the proto, new, and inheritTable properties.) Like JS, any number of Person instances can be created, and they will all share common 'eat' and 'die' methods from their ancestors. In both of the above cases, a full-fledged instance with all the methods is not copied upon creation, but instead a lightweight instance is created with pointers that the language can use to find 'inherited' methods or properties. --Apple-Mail-4--52668417--