
Prototype based vs. class based inheritance - brandonkm
http://stackoverflow.com/questions/816071/prototype-based-vs-class-based-inheritance/816075#816075
======
silentbicycle
See: <http://www.c2.com/cgi/wiki?ClassesPrototypesComparison>

In my experience, prototype-based OOP is less prone to the typical OOP over-
analysis - if you just need one object that does something, _you just assemble
it, that's it, problem solved_. Since the default stance isn't designing a
generic class for all possible subtypes that exhibit related behavior and blah
blah blah, there's less push toward overthinking things.

Prototype-based OOP is also well-suited to runtime modification, since the
underlying implementation is usually simpler, but that's a distant second to
the above benefit. And while prototypes are sometimes assumed to be less
efficient than classes, look at the research from Self* - While some popular
languages have poor implementations, it's not _inherently_ less efficient.

Also, I suspect prototypes integrate more smoothly with non-OOP code than
classes, based on experience with Lua (which isn't strictly OOP, but typically
uses prototypes). To some extent, this blurs with dynamic typing, though -
there's only one statically typed + prototype-based OOP language I know of,
Günther Blaschek's Omega (described in _Object-Oriented Programming With
Prototypes_).

* <http://selflanguage.org/documentation/published/index.html> Some of the people involved later worked on the "JVM". Perhaps you've heard of it?

~~~
demallien
_In my experience, prototype-based OOP is less prone to the typical OOP over-
analysis - if you just need one object that does something, you just assemble
it, that's it, problem solved. Since the default stance isn't designing a
generic class for all possible subtypes that exhibit related behavior and blah
blah blah, there's less push toward overthinking things._

But that's not really a property of prototype languages - it's a property of
duck typing. For example, Ruby - a non prototype language - can implement
exactly the same idea. Take an instance of a class, and add a method
specifically to that object - no problems. Critically, the thing that makes
this possible is the fact that evaluation of the existence of the method is
made at call time, not at compile time.

~~~
silentbicycle
Dynamic and duck typing does help quite a bit there, but I think the default
stance of prototypes rather than classes also makes a difference.

The way I write object-centric code in Lua feels very different from in
Python, even though both languages are dynamically typed (and otherwise fairly
similar). It probably has to do with conventions / what's "Pythonic". I
haven't used Ruby enough to comment.

------
russellallen
Some thoughts:

Given a sufficiently flexible and late-bound class system (like Smalltalk's),
the differences between prototypes and classes can blur.

But in general I would say that it is easier to build classes on top of
prototype systems than vice versa, which is one argument for prototypes.

All prototype implementations aren't the same, though, any more than Smalltalk
and C++ both have the same class systems! Javascript and Self are quite
different in some ways, especially when it comes to delegation (ie
inheritance) and iolanguage and research such as Kevo are different again.

Despite the first answer to the linked question, I don't think that either
class based or prototype based languages are easier to write a VM for.

What attracts me most is that prototype systems are conceptually simpler in an
Occam's Razor sort of way. Instead of needing two concepts: classes and
instances, we only need one: objects.

~~~
wvenable
> What attracts me most is that prototype systems are conceptually simpler in
> an Occam's Razor sort of way.

That's true, but I find you end up having to make the difference. Yes,
prototype inheritance is conceptually simpler but in practice it's more
complex. In JavaScript, for example, OO code tends to be harder to follow and
includes more boilerplate code. You have to make up for the simplicity of the
platform in order to get your work done. In more traditional OO languages,
inheritance might be more limited but it's also more straight forward and
easier to implement, calling parent class methods is build in, and the "this"
reference works consistently.

~~~
wkornewald
JavaScript has the worst form of prototype inheritance I've ever seen. All the
boilerplate code is not the fault of prototypes, but of JS. Also JS prototypes
are insanely limited. You can't have multiple delegates and you can't change
delegates at runtime. JavaScript's inheritance actually smells like some
broken state between class based inheritance and prototypes. It has none of
the advantages of either and combines the disadvantages of both. I'll make a
longer blog post explaining how prototypes are supposed to work and what their
real advantages are. You'll see that JS inheritance is a huuuge design failure
and that nobody should ever mention prototypes and JavaScript in the same
sentence.

~~~
wvenable
I've studied other prototype languages (Io for example), but JavaScript is the
only one that I use on a regular basis or in a professional capacity. I
imagine for the vast majority of developers, JavaScript is their only
introduction to prototype inheritance.

~~~
wkornewald
Yeah, and that's a real shame because those developers will get a really bad
impression of prototypes (unless they only use one of the class emulation libs
and never learn about prototypes, of course).

------
mln
this is what Guy Steele has to say.
[http://people.csail.mit.edu/gregs/ll1-discuss-archive-
html/m...](http://people.csail.mit.edu/gregs/ll1-discuss-archive-
html/msg03277.html)

~~~
eliben
One of the links from this page mentions this:
<http://okmij.org/ftp/Scheme/oop-in-fp.txt>, where the author presents a
simple example of implementing an object using closures:

    
    
      (define (make-point-2D x y)
        (define (get-x) x)
        (define (get-y) y)
        (define (set-x! new-x) (set! x new-x))
        (define (set-y! new-y) (set! y new-y))
        (lambda (selector . args)     ; a dispatcher
            (case selector
              ((get-x) (apply get-x args))
              ((get-y) (apply get-y args))
              ((set-x!) (apply set-x! args))
              ((set-y!) (apply set-y! args))
              (else (error "don't understand " selector)))))
    

Which is curiously similar to the canonical object implementation of SICP in
section 3.2:

    
    
      (define (make-account balance)
        (define (withdraw amount)
          (if (>= balance amount)
              (begin (set! balance (- balance amount))
                     balance)
              "Insufficient funds"))
        (define (deposit amount)
          (set! balance (+ balance amount))
          balance)
        (define (dispatch m)
          (cond ((eq? m 'withdraw) withdraw)
                ((eq? m 'deposit) deposit)
                (else (error "Unknown request -- MAKE-ACCOUNT"
                             m))))
        dispatch)

------
bgriggs1
Here's a useful comparative demo that makes this a little easier to
differentiate: <http://alexsexton.com/inheritance/demo/>

------
yycom
Can someone point to a non-trivial example using prototypal inheritance?

