# Prototype-Based Inheritance (#214)

**URL:** <https://www.ruby-forum.com/t/prototype-based-inheritance-214/171897>\
**Category:** Ruby\
**Created:** [July 10, 2009, 11:25pm UTC](https://www.ruby-forum.com/t/prototype-based-inheritance-214/171897 "2009-07-10T23:25:14Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![danmcb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/13edae/32.png) [@danmcb](https://www.ruby-forum.com/u/danmcb)\
**Post date:** [July 10, 2009, 11:25pm UTC](https://www.ruby-forum.com/t/prototype-based-inheritance-214/171897/1 "2009-07-10T23:25:14Z")

</div>

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

The three rules of Ruby Q.:

1. Please do not post any solutions or spoiler discussion for this  
quiz until 48 hours have elapsed from the time this message was  
sent.

2. Support Ruby Q. by submitting ideas and responses  
as often as you can!  
Visit: [http://rubyquiz.strd6.com/suggestions](http://rubyquiz.strd6.com/suggestions)

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem  
helps everyone on Ruby T. follow the discussion. Please reply to  
the original quiz message, if you can.

RSS Feed: [http://rubyquiz.strd6.com/quizzes.rss](http://rubyquiz.strd6.com/quizzes.rss)

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

## Prototype-Based Inheritance (#214)

Ayú Rubyists,

This week’s quiz is to implement prototype-based Inheritance[1](http://en.wikipedia.org/wiki/Prototype-based_programming). In  
prototype-based inheritance objects gain their properties from other  
objects, not from class hierarchies. Here’s a code example to  
illustrate setting a prototype explicitly:

```
pele = {:name => "Pele", :sport => "football", :position => 

```

“Forward”}  
pele\_jr = {:name =\> “Pele Jr.”}  
pele\_jr.prototype = pele  
pele\_jr.name # =\> “Pele Jr.”  
pele\_jr.sport # =\> “football”  
pele\_jr.position # =\> “forward”

You may notice that this doesn’t work: `NoMethodError: undefined method 'prototype' for {:name => "Pele", :sport => "football", :position => "Forward"}:Hash`. If it did work then there’s not much  
for you to do on this quiz!

Hopefully this example illustrates some of the basics of how  
prototype-based inheritance works: there is one prototypical football  
player and other players defer to that player if they are queried for  
an attribute that hasn’t been specified. This relates closely with our  
intuitions and how we discuss things “it’s kind of like Starbucks,  
except the drinks are bigger”

```
new_coffee_shop.prototype = starbucks
new_coffee_shop.drink_size += 1

```

Have Fun!

---

<div class="post-metadata">

**Author:** ![danmcb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/13edae/32.png) [@danmcb](https://www.ruby-forum.com/u/danmcb)\
**Post date:** [July 12, 2009, 7:50pm UTC](https://www.ruby-forum.com/t/prototype-based-inheritance-214/171897/2 "2009-07-12T19:50:47Z")

</div>

> ```
> pele = {:name => "Pele", :sport => "football", :position => "Forward"}
> pele_jr = {:name => "Pele Jr."}
> pele_jr.prototype = pele
> pele_jr.name # => "Pele Jr."
> pele_jr.sport # => "football"
> pele_jr.position # => "forward"
> 
> ```

What about:

class Hash

```
def prototype=(prototype)
    merge!(prototype) {|k,o,n| o}
end

def method_missing(name, *args, &block)
    if has_key?(name)
        val = fetch(name)
        case val
        when Proc
            return val.call(self, *args)
        end
    end
    if name.to_s =~ /^(.*?)=$/
        meth = :[]=
        name = $1.intern
    else
        meth = :[]
    end
    margs = [name, *args]
    margs << block if block
    send(meth, *margs)
end

```

end

This would allow you to do something like:

pele\_jr.age = 20  
pele\_jr.foo = lambda {|this, a| this.age + a}  
pele\_jr.foo(10) #=\> 30

---

<div class="post-metadata">

**Author:** ![danmcb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/13edae/32.png) [@danmcb](https://www.ruby-forum.com/u/danmcb)\
**Post date:** [July 13, 2009, 5:29pm UTC](https://www.ruby-forum.com/t/prototype-based-inheritance-214/171897/3 "2009-07-13T17:29:39Z")

</div>

On Sunday 12 July 2009 12:49:55 pm lith wrote:

> ```
> def prototype=(prototype)
> merge!(prototype) {|k,o,n| o}
> 
> ```

I based my implementation on Javascript, and one of the nice properties  
there  
is that the prototype can change later. So, for example, in my  
implementation:

irb(main):005:0\> pele.favorite\_food = ‘hamburger’  
=\> “hamburger”  
irb(main):006:0\> pele\_jr.favorite\_food  
=\> “hamburger”  
irb(main):007:0\> pele  
=\> {:name=\>“Pele”, :sport=\>“football”, :position=\>“Forward”,  
:favorite\_food=\>“hamburger”}  
irb(main):008:0\> pele\_jr.favorite\_food = ‘cheeseburger’  
=\> “cheeseburger”  
irb(main):009:0\> pele\_jr.favorite\_food  
=\> “cheeseburger”  
irb(main):010:0\> pele.favorite\_food  
=\> “hamburger”

Of course, this is slower, but more powerful, I think.

> ```
> when Proc
> return val.call(self, *args)
> end
> 
> ```

[snip]

> This would allow you to do something like:
> 
> pele\_jr.age = 20  
> pele\_jr.foo = lambda {|this, a| this.age + a}  
> pele\_jr.foo(10) #=\> 30

Nice touch…

Here’s mine:

module Prototype  
attr\_accessor :prototype  
def method\_missing \*args  
prototype.public\_send \*args  
end  
end

That’s more generic than just hashes. Mix it into Object and it works on  
anything. Of course, it’s not exactly convenient to have to define new  
values  
like this:

pele = Object.new  
class \<\< pele  
attr\_accessor :name  
end  
pele.name = ‘Pele’

It also severely limits what you can do with some of the builtin classes  
like  
Fixnums that can’t have a metaclass.

And of course, to make it saner for the example (and because OpenStruct  
won’t  
cooperate), I can do this:

class Hash  
include Prototype  
def method\_missing name, \*args  
if has\_key? name  
self[name]  
elsif name =~ /.=$/  
self[name.to\_s.chomp(’=’).to\_sym] = args.first  
else  
super  
end  
end  
end

---

<div class="post-metadata">

**Author:** ![danmcb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/13edae/32.png) [@danmcb](https://www.ruby-forum.com/u/danmcb)\
**Post date:** [July 14, 2009, 4:05pm UTC](https://www.ruby-forum.com/t/prototype-based-inheritance-214/171897/4 "2009-07-14T16:05:55Z")

</div>

Hi,

a simple Solution, which works for static Prototypes:

module Prototype  
def method\_missing name, \*args  
# if we have a prototype forward to it’s methods  
# else propagate method missing upwards  
if defined?(@ **proto** ) && @ **proto**  
@ **proto**.send name,\*args  
else  
super  
end  
end

def set\_prototype pt  
# clone the prototype, so we can freely modify  
# it’s attributes w/o interference with others  
@ **proto** = pt.clone  
end  
end

As said above this is a simple solution, but it should work for all  
classes  
and is easily written.  
But it comes at the cost of duplicating arbitrarily complex objects  
(perhaps  
many times) and just allows static prototypes.  
I couldn’t come up with a solution which filters writing access to the  
proto-  
type (apart from simple regexing) but allows modification from the  
parentside.  
Possibly one could use observers and method\_defined hooks for this, but  
the  
complexity would be rather high on this way.

Best regards,  
Thorsten

---

<div class="post-metadata">

**Author:** ![danmcb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/13edae/32.png) [@danmcb](https://www.ruby-forum.com/u/danmcb)\
**Post date:** [July 20, 2009, 5:06am UTC](https://www.ruby-forum.com/t/prototype-based-inheritance-214/171897/5 "2009-07-20T05:06:03Z")

</div>

Daniel M. wrote:

> ## Prototype-Based Inheritance (#214)

I decided to give it a shot:

require ‘ostruct’

class Prototype \< OpenStruct  
attr\_reader :prototype

```
def prototype=(new_prototype)
  if new_prototype.prototypes.include?(self)
    raise ArgumentError, "circular prototype chain"
  end
  @prototype = new_prototype
end

def prototypes
  if @prototype.nil?
    []
  else
    [@prototype] + @prototype.prototypes
  end
end

def delete_slot(name)
  name = name.to_sym
  if @table.has_key?(name)
    meta = class << self; self; end
    meta.send(:remove_method, name)
    meta.send(:remove_method, :"#{name}=")
  end
  delete_field(name)
end

def method_missing(mid, *args)
  if @prototype.nil? || mid.id2name =~ /=$/
    super
  else
    @prototype.send(mid, *args)
  end
end

```

end

Most of the functionality is inherited from OpenStruct. The trip down  
the prototype chain happens in method\_missing. A short IRB session  
should explain the usage:

> > require ‘prototype’  
> > true
> 
> > starbucks = Prototype.new(:name =\> “Starbucks”, :drink\_size =\> 3)  
> > =\> #\<Prototype name=“Starbucks”, drink\_size=3\>
> 
> > new\_coffee\_shop = Prototype.new(:name =\> “New”)  
> > =\> #
> 
> > new\_coffee\_shop.prototype = starbucks  
> > =\> #\<Prototype name=“Starbucks”, drink\_size=3\>
> 
> > new\_coffee\_shop.drink\_size  
> > =\> 3
> 
> > new\_coffee\_shop.drink\_size += 1  
> > =\> 4
> 
> > new\_coffee\_shop.drink\_size  
> > =\> 4
> 
> > new\_coffee\_shop.delete\_slot(:drink\_size)  
> > =\> 4
> 
> > new\_coffee\_shop.drink\_size  
> > =\> 3
> 
> > another\_coffee\_shop = Prototype.new(:name =\> “Another”)  
> > =\> #
> 
> > another\_coffee\_shop.prototype = new\_coffee\_shop  
> > =\> #
> 
> > another\_coffee\_shop.drink\_size  
> > =\> 3
> 
> > another\_coffee\_shop.prototypes  
> > =\> [#, #\<Prototype name=“Starbucks”,  
> > drink\_size=3\>]
> 
> > starbucks.prototype = another\_coffee\_shop  
> > ArgumentError: circular prototype chain  
> > from ./prototype.rb:8:in `prototype=’  
> > from (irb):23
> 
> >

-Matthias

---

<div class="post-metadata">

**Author:** ![danmcb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/13edae/32.png) [@danmcb](https://www.ruby-forum.com/u/danmcb)\
**Post date:** [July 26, 2009, 8:21pm UTC](https://www.ruby-forum.com/t/prototype-based-inheritance-214/171897/6 "2009-07-26T20:21:29Z")

</div>

Prototype based inheritance is used in many programming languages,  
JavaScript being the most well known. As demonstrated in the solutions  
this week there are a few different techniques that can be used.

lith provided a solution that merges the prototypes data into the  
inheriting Hash when the prototype method is called. Special care is  
taken to not overwrite fields in the inheriting Hash. This use of  
`merge!` accomplishes that elegantly:

```
def prototype=(prototype)
  merge!(prototype) {|k,o,n| o}
end

```

Another feature of lith’s solution is the ability to use blocks as  
values in the Hash. This allows the objects to inherit methods as well  
as simple values.

```
starbucks = {:drink_size => 3, :cost => lambda {|this| 

```

this.drink\_size + 1}}  
new\_coffee\_shop = {:drink\_size =\> 1}  
new\_coffee\_shop.prototype = starbucks

In this case the new\_coffee\_shop’s cost will be 2. It inherits the  
cost method from the parent.

David M.'s solution used the JavaScript style of prototype  
inheritance, where rather than merging the values of the parent into  
the child object, the child object maintains a reference to the  
parent. An advantage of this technique is that updates in the parent  
are carried through to the child, unless the child overrides that  
property. There is a trade off however, maintaining the link back to  
the parent means an extra method lookup. This isn’t usually an issue,  
but if you are working with a deep nesting and inheriting many  
attributes it can add up, so it’s important to be aware of.

Thorsten H. submitted a simple solution that maintained a reference  
to a copy of the prototype object. This prevents modifications in the  
prototype from being reflected in the child. The simplicity of the  
implementation comes at a cost though, duplicating some objects may be  
very expensive.

Matthias R. also submitted a solution this week. Matthias’s  
solution extends OpenStruct to handle converting method calls into  
hash keys. Like David’s solution Matthias’s solution maintains a  
reference to the prototype object. In addition Matthias gives us a  
`prototypes` method that returns an array of all the prototypes for  
this object. This is used to detect a circular inheritance chain,  
which almost always means an error. Matthias also adds a method to  
delete a property. When a property is deleted from a child the child’s  
prototype’s property will shine through.

There were several interesting takes on this week’s quiz. Some of the  
decisions, like whether to have fixed prototypes by copying/merging or  
dynamic prototypes by maintaining references are mutually exclusive,  
but other techniques from these solutions can be combined together,  
like allowing blocks, deleting properties, or maintaining a list of  
prototypes. When deciding which type of inheritance best fits your  
next applications needs it is important to consider the trade offs  
between simplicity and efficiency as well as speed and memory.

Thank you lith, David, Thorsten and Matthias for your solutions to  
this week’s quiz!
