Property vs Behavior inheritance

John J Barton johnjbarton at johnjbarton.com
Thu Dec 15 09:17:12 PST 2011


(I know the language experts know all this, I'm spelling it out for fellow
amateur 'classless' fans)

After using (and liking) selfish I understand why prototypical inheritance
via simple references is not an effective alternative to classes.

The new Foo/Foo.prototype JavaScript idiom sets up a lookup table like this:

[[Prototype]] -----> [[Prototype]] ------> [[Prototype]] -------> null
myProps           |  parentProps           grandProps
                  |
                  |
[[Prototype]] ----+
myProps

That is, two instances share a parent base class.

If you use these instances as values for a .prototype property or if you
use these instances as the first argument to Object.create(), then these
instances act as "classes". The [[Prototype]] links set up a
single-inheritance "vtable".

However, repeating the process a second time fails. That is, using the
object instances from the preceding paragraph as 'classes' almost always
fails to produce a useful result.  Every class is an object, but not every
object is useful as a class.

The reason is simple: 99% of the time you want base class functions to be
inherited but not base class data values. In setting up
"objects-that-will-be-classes" we can consciously avoid data values. I did
not say this above, but most readers will imagine that all of the objects
in the diagram above have only functions. That is essential what we mean
when we thing of these objects as classes: no data properties.

But once we use these classes to create instances, those instances will
very likely have data. Thus they will no longer be effective as 'classes'.

In real JS code there is no way to tell if an object is intended to be a
class. Objects that implement useful behavior seem like great candidates
for "prototypical inheritance".  This burns every JS developer at one time
or another. And probably much more than most will admit.

JS projects address this issue by conventions and they can be successful.
One in particular is 'selfish': the split between behavior and data is
created by declaring behavior but implementing all data values imperatively
in initialize().  It is convention only.

Class-based languages solve this by building the 'behavior' or function
layer differently from the 'data' layer. The functions are placed in vtable
data structures referencing base class vtables; data values are
concatenated across all classes as properties for the instance.

Classless solutions need a compelling solution to this issue, that is, an
operation on a list of vanilla objects that yields a class-like object. Any
such operation will fail in some cases, just like class-based solutions
fail sometimes (when you really want to share data across classes). But a
solution is needed for the 99% of the time when you don't want data sharing.

jjb
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20111215/0f8fe734/attachment.html>


More information about the es-discuss mailing list