Eric Elliott eric at ericleads.com
Fri Jun 28 18:06:37 PDT 2013


"Gang of Four says prefer composition to inheritance, not avoid inheritance
 altogether."

That wasn't such an easy choice in Java or C++. It's a down-right trivial
choice in JavaScript.

"As you suggest near the end of your last reply, you can use composition or
injection with any of those constructors in the inheritance hierarchy to
add or override behavior."

When you're working in an established codebase, it's much harder to go
against the grain of momentum than your reply suggests.

For example, project x had been using Backbone.View.extend(),  and has a
6-generation class hierarchy. Now the root level's constructor function is
doing something that the youngest child needs to override -- but every
other ancestor relies on that functionality, and the youngest relies on
functionality of its ancestors in-between. (This was an actual situation in
an actual codebase with over 100,000 lines of client-side JavaScript).

Since all the descendant classes relied on the implementation of the
ancestors (through .super() calls), the mess was not easy to detangle. It
wasn't simply a matter of grafting some stuff on to an object after the
fact. Single-parent hierarchies make it hard to do selective inheritance.
(I refer you again to the gorilla banana problem).

If the code had relied less on sub-classing views, and more on mixins, this
problem never would have come up.

"Rely on an interface, not an implementation" - violated by sublassing and
super().

"If the argument is against the class extends super syntax in ES6, I agree
it's not necessary in ES.  But as others have pointed out, it's an opt-in
feature that we won't be forced to use"

See the pit of dispair vs pit of success argument I made in my last reply.

"I haven't seen coupling as a *problem* withinheritance per se so much as
that a constructor is doing *any* work at all - by which I mean
side-effects"

I could not agree more about avoiding side-effects, but inheritance (even
without instantiation side-effects) still suffers from other problems.
Notably the specialization problem of single-ancestor inheritance, which
leads to collections of similar objects with unexpectedly divergent
properties. Composition / mixins give you easy selective inheritance. (See
also, the gorilla banana argument).

Yes, you can selectively inherit by copying properties, but not if your
constructors are used for private state (which is often a good thing -- it
allows you to hide implementation details so that users of your API can
program to your interface, not your implementation).

If you're using patterns like the ones found in Stampit, you don't have
that problem, either.

- Eric


On Fri, Jun 28, 2013 at 5:07 PM, david kaye <dfkaye at yahoo.com> wrote:

> Eric -
>
>
> On class-based inheritance
>
> Gang of Four says prefer composition to inheritance, not avoid inheritance
> altogether.
>
> As you suggest near the end of your last reply, you can use composition or
> injection with any of those constructors in the inheritance hierarchy to
> add or override behavior. It does not follow that we should never use an
> inheritance hierarchy for generally shared or default behavior.
>
> If the argument is against the class extends super syntax in ES6, I agree
> it's not necessary in ES.  But as others have pointed out, it's an opt-in
> feature that we won't be forced to use (big thank you to everyone for
> supporting backward compatibility).  As David Bruant noted, some prefer not
> to use Object.create() and just use new function() instead (I'm one of them
> - I'm guilty).
>
> If the argument is against them in all cases, we still have to use care
> with mixins (see ActiveRecord for an extreme case) and interfaces, etc., as
> even a change to a trait or interface can have consequences downstream.
>
>
> Out here in Userland
>
> I've seen the same pathology you describe in several codebases - it also
> happens with CSS descendant rules and id selectors, !important rules and
> inline style attributes to override them *this one time*.
>
> But, I haven't seen coupling as a *problem* with inheritance per se so
> much as that a constructor is doing *any* work at all - by which I mean
> side-effects - which is an argument for using Object.create - which I now
> note with irony.
>
> The one thing that saved us from dread of *OMG we have to re-visit
> everything* has been reliance on unit tests - test-driven-development, or
> test-during-development really does reduce the fear of later confusion -
> but that's another discussion entirely.
>
>
> Sorry for preaching to the choir and/or ruffling feathers
>
> DFKaye
>
>
>
>   ------------------------------
>  *From:* David Bruant <bruant.d at gmail.com>
> *To:* Eric Elliott <eric at ericleads.com>
> *Cc:* es-discuss <es-discuss at mozilla.org>
> *Sent:* Friday, June 28, 2013 3:55 PM
> *Subject:* Re:
>
>  Le 29/06/2013 00:14, Eric Elliott a écrit :
>
>  "I'm however very interested if you could take a look at the current
> proposal and tell if you can pin down how the current proposal makes
> classes harmful for code maintainability."
>
> Basically, my argument is that the whole paradigm of a class with a single
> ancestor, and any mention of that ancestor in the implementation of the
> child (referring to the parent in the constructor, for instance), is
> fundamentally flawed and problematic. `extends` harms code maintainability
> by virtue of creating the brittle hierarchy / gorilla-banana problem I've
> already described.
>
> The problem isn't how it's done in JavaScript or ES6. The problem is that
> it's done at all.
>
> Class gets people thinking in a fundamentally broken paradigm for good OO
> design
>
> The rest of JavaScript remains. ES6 classes are just a sugar on top of the
> ES5 runtime concepts (objects with [[Prototype]], [[Get]], [[Set]], etc.).
> People already think in a broken way when it comes to software. Software
> is hard. Lots of people model data inside strings. I believe this is a much
> bigger problem than classes. What's the solution for stringly typed code?
>
>  I saw a recent example of one of the problems with single-ancestor
> inheritance in a talk. I wish I could remember which one.
>
> I believe it was this talk by Angus Croll
> https://speakerdeck.com/anguscroll/the-why-and-how-of-mixins-in-flight
>
>  The illustrations were great:
>
> Animal
>   - Walking
>     - Monkey
>     - Human
>   - Flying
>     - Bird
>     - Bee
>    - Swimming
>     - Fish
>     - Whale
>
> Now we need alligator and duck.
>
> I understand that JavaScript doesn't restrict you from doing things like
> mixins as well... but when you're 14 months into a project, and THEN you
> have to add the alligator, suddenly you're mixing paradigms in ways that
> diverge significantly from the style of the rest of the code base. At this
> point, the code is already arthritic and brittle. Fitting these things in
> at this point is a lot less trivial.
>
> Classes and the single-ancestor pattern are limited in the sort of objects
> they can model. Animals are such an example.
> But you can model other simpler things that don't have properties that
> cross over. Classes can work for these cases.
> I believe that these cases are numerous and classes can work for them.
>
> Classical inheritance is a problem when that's the only tool you have. But
> if you have a decent understanding of what you're trying to model, you can
> use classes when that fits and other more appropriate mechanisms when
> they're available. The very tool you use to model something can already be
> of help to others to understand the "shape" of what you're modeling.
>
>   If you're relying on things like super in the rest of the code, how
> does the new stuff properly invoke the constructors of multiple ancestors
> which are designed to be single ancestors?
>
> Does the ES6 super has the same issue than the Java one? I really don't
> feel I have enough expertise in the matter to say yet.
>
>   I can tell you how I've seen these situations handled in the real
> world, virtually everywhere the problem has cropped up (pretty much
> everywhere that class was relied on heavily). Massive refactors. Code
> rewrites. Lots of wasted time.
>
> Yes, when the wrong tool is used for a job, people pay it later. It also
> happens in JavaScript. In my experience, it's often more a problem of not
> understanding your model enough when first writing the code. In my
> experience again, it's hard to plan everything in advance and choosing
> class or not class is rarely the heart of the problem when you've
> mis-modeled your software.
>
>   Class sugar might save developers a few keystrokes today, but it will
> come back to bite them hard later. Lots of people are paying for Backbone's
> .extend().
>
> If it added value, that would be one thing. But it doesn't actually do
> anything that couldn't have been done just by replacing it with a
> constructor that produced objects that could be passed into those
> constructors to produce new objects.
>
> This sort of argument leads us nowhere. By that argument, we can remove
> maybe 70% of the JS built-ins. All the Math functions and constants can go,
> all Array.prototype algorithms... Object.create isn't even necessary if you
> have functions and 'new', etc.
> Classes offer a nice sugar to cover *some* use cases, *some* modelisation
> cases. Among expert-enough people, using classes may become the sign of
> simple models (when there is no need for specialization) or simple
> specialization patterns. That's a good thing. It's not big, but it's a good
> thing.
>
>   I have seen the problems in code at Adobe, at Tout, and at BandPage (my
> last three jobs, that all used Backbone).
>
> I would be interested in see code samples describing your problem. I do
> believe you and I agree with you by intuition, but I would love to have a
> fully-fleshed example to study it and fully understand it to understand if
> some code maintainability issues.
>
>   The problem isn't with Backbone's particular implementation. I had the
> same problems in C++, Java, and with John Resig's Simple Inheritance in
> JavaScript.
>
> The problem isn't with the ES6 implementation. It's the whole paradigm.
>
> No, the problem is when people limit the way they think about software
> through this only one paradigm. If this paradigm is here alongside others,
> I don't see the problem. People have the choice. Some will make mistakes,
> but how different is it from today?
>
> David
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20130628/1e3aac32/attachment-0001.html>


More information about the es-discuss mailing list