Classical inheritance is obsolete

# Norbert Lindenberg (12 years ago)

Giving this thread a subject, based on the title of the talk referenced below.

# Axel Rauschmayer (12 years ago)

On Jun 29, 2013, at 20:12 , Eric Elliott <eric at ericleads.com> wrote:

If I were advertising, there are better places to do it, and better ways. I feel like adding class to JS would be detrimental to the language and the users of the language, and I feel that the previous discussions on the topic did not make a strong enough argument against it.

Let me try to paraphrase what you are criticizing about ECMAScript 6 classes:

  1. Single inheritance doesn’t always cut it, we need some kind of multiple inheritance (mixins/traits/...).

  2. ES6 classes prevent mixins/traits/...

  3. ES6’s implementation of single inheritance is ugly.

  4. We have everything we need. Let’s all agree on a common, elegant library.

Comments on these points:

(1) I don’t think anybody disagrees with this point. That’s why mixins/traits/... are firmly on the roadmap for versions after ECMAScript 6. For one-dimensional taxonomies, single inheritance is perfectly adequate. If you have cross-cutting concerns, you can model them as mixins. There are many more interesting OOP mechanisms (before/after/around methods, cooperative methods, meta-object protocols, etc.). Thus, ES6 classes are but the simplest possible first step.

(2) ECMAScript 6 classes don’t prevent mixins. Certainly not in the future, but not even now – you can extend an object (instead of a function) and that object can be generated by your mixin library of choice:

class SubClass extends mixin(SuperClass, Mixin1, Mixin2, ...) { ... }

(3) In my opinion, that’s the most valid criticism of ES6 classes: They look like object exemplars, but desugar to function exemplars. That will probably sometimes confuse people. On the other hand, backward compatibility matters! And constructors are the most commonly used and most optimized inheritance mechanism that JavaScript currently has. With more configurability coming up in ES7 or later, it is also conceivable that at some point in the future, we’ll be able to switch to a different desugaring for classes (per module).

(4) The JavaScript ecosystem suffers from a lot of NIH. If we couldn’t agree on a common library in the years since ECMAScript 5’s existence, it’s highly unlikely that it will ever happen. That’s why I think ES6 classes are so important: they enable us to exchange code between frameworks that, at the moment, have completely incompatible inheritance APIs. Object.observe helps, too, because it obviates the need for hacks to enable data binding. Similar to modules, I’m pretty sure we’d be incapable of agreeing on a common standard without ECMAScript 6.

CONCLUDING THOUGHT: I don’t think you appreciate how hard it was to reach the consensus for ECMAScript 6 classes (lots of incredibly long, incredibly passionate discussions!). Would I have done classes differently? Yes. But the consensus enables us to have a solution that is good enough, which (IMO) is far better than having nothing.

# Dmitry Soshnikov (12 years ago)

I agree, this topic fits better for JS forums. There is no big need to discuss here "prototypes vs classes" (it's simply about code reuse with different styles, and is searchable on many JS forums/articles). This mailing list is for the language design and implementation.

Dmitry

# David Bruant (12 years ago)

Le 30/06/2013 04:22, Chris Ryan a écrit :

Do we need classes at all? In my opinion, given that the concept is implemented in a clear manner and it is possible to be powerful enough to be of use in favour of prototyping (and developing based on the prototypal concept instead), then yes, it would have my support. However, my major gripe with the current classes proposal (and in fact with a few other proposals too, but that's a different story) is that it's just syntactic sugar added for the sake of it - it doesn't add any sort of functionality that cannot be implemented another way with the current toolset, and this contraption will only add complexity and confusion to the language.

That's a design goal. I would oppose any class proposal that would require new runtime constructs. The fact that it's just sugar is a good occasion for people to learn how the class syntax desugars in "plain JS" and learn how the JS runtime works under the hood.

Developers from object-oriented background will inevitably assume because ES6 has native classes and its syntax is almost exactly the same to what they are used to, that they will behave in a similar manner to the classes that they are used to in Java, C#, C++, etc. While it is obviously wrong to assume so, naturally they will apply similar methods of doing things that they did in their old language that used classes extensively, causing many issues when their code doesn't behave in the same manner.

Some people will misuse new features of the language. It's already the case with current features. Some people also try to implement classes with awful libraries. If anything, the class syntax is a way to show these people how it should be done in the language given the very language idioms.

It's best understood when we apply the duck test to this concept:

Does it look like a duck? Does it swim like a duck? Does it quack like a duck?

If the answer to all three was yes, then developers are most likely to assume that it indeed the "duck" that they are used to - only that the animal is indeed not a duck at all. What is the point of misleading developers into believing that it is what think it is, only for it to not quite work how it describes: isn't that what a scam is? There is a case in that developers from other programming languages will be able to feel more "at home" with ECMAScript - but shouldn't we be trying to get them to understand what it's really about

We are. A lot of us (regulars of es-discuss) are. On my side, I've been contributing heavily to MDN (because it's a wiki and CC-licenced) over the last few years. I've been giving professional training. I'm running a local JS meetup in my city. Recently, I've given 2 conferences even traveling on my own money to do so. I know others here are doing a lot too. Dmitry Soshnikov has an excellent blog that explains the language in great details. Axel Rauschmayer does too. He also runs a mailing-list curating excellent content related to JS. I've only been describing a small fraction of what people do to educate others. Yes, we would all love to have everyone understanding the language. We're working on it. If you want to write content explaining how different object modelisation problems are solved in JS, your content is most welcome on MDN or WebPlatform.org or your own blog at your preference. If you have the expertise of the subtleties of object models in different languages, please write guides. Write an "JavaScript object model for Java-ers", "JavaScript object model fro C++-ers", tutorial, etc.

not abstracting it into something that sort of looks like what they are used to, but don't quite work like that?

I believe that what the class syntax desugars to is better that what most class libraries are trying to do.

Regardless of where they come from, most developers are unhappy to have to change their thinking about how to program - I personally think that it's more preferable to let them know upfront that it's not just another language that's similar enough; ECMAScript is different enough in my opinion to warrant this distinct difference in direction.

Yes and no. As it turns out, the following pattern is close enough to what most people expect of a class in most cases:

 function Animal(){
     this.age = 0;
     setTimeout( () => {this.age++}, 1000 )
 }

 Animal.prototype = {
     walk: function(){
         console.walk();
     }
 }

If that is so, why having newcomers search for hours to find that this pattern fits their need? Why not provide that with a syntax they're familiar with? It doesn't prevent to learn how the language can be otherwise used. Maybe they'll find your "JavaScript for Java-ers" quickly. I heard that MDN has been doing major improvement to its SEO recently ;-)

It also creates confusion as to which method shall be used to program

  • having multiple methods to do the same thing is the classic root of debate, confusion, misleading and downright incorrect information being spread around, and authority figures being "in one camp", generating mass followings and arguments between the two factions.

Maybe the (intial!) confusion is a good thing if it gets people to think about their own practice. If the web had excellent CC-licenced resources to help people make a good decision it would reduce the confusion you're talking about.

If we don't need classes, there are no features introduced that do not simplify programming significantly (e.g. destructuring assignment), nor allow functionality not previously possible in ECMAScript (e.g. modules), why should we press ahead with something that will just further add fear, uncertainty and doubt into the minds of programmers, will make the language yet more complicated to learn than before (especially to people completely new to programming and the object-oriented paradigm)

Write resources to help people make the right choice and learn right. The language isn't learned by people reading the spec from to bottom then going to a text editor. People read resources on the web and learn from code written by others.

and goes against quite a few other concepts in use in ECMAScript code (i.e. functional programming)?

JS is a rich language that allows different styles of programming. Nothing wrong with that. At scale, I prefer the risk of making wrong choices to a too restrictive newspeak.

It's something that is just not needed for the development and growth of the language - we have so many other things that we can branch off and build upon: classes is just too much work for way too little gain.

Too much work for whom? Classes are a convenient sugar for experts and somewhat reassuring to people coming from other OO languages. That's enough of a gain for me. I'll keep contributing to MDN, give training and talks to compensate the potential confusion.

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. First of all, since they (the current builtins) are already there, it's pretty difficult to remove them.

I'm quite aware ;-)

The point of them (and in fact, any form of syntactic sugar) is to make ideas more simple to express while not losing any functionality. Whether classes do add simplicity is debatable

Just to clarify, I didn't say that classes added simplicity. I said that they are a good tools for simple models. And I said that it's a nice sugar for expert-enough people. Whether it adds simplicity or complexity is too hard a question for me to have an opinion on yet.

however with more options, I would ought to believe comes more complexity, especially since it is not inherently more concise to express your ideas through the current classes proposal versus through prototyping.

But it's much clearer. Today, everything is object and function declarations. It isn't well-defined when people are doing a class-like code sharing or when they're doing something else. The class syntax makes that pattern really clear. It also makes the single-inheritance use case very clear unlike what people have needed to come up with until today: nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor

Classes remove the boilerplate needed for class-like code sharing and add a clear visual identity. Reading lots and lots of JS, I am convinced it'll make my life easier.

The vast majority of the current "sugar" methods provide a much simpler method of doing things than what is possible without it (e.g. most of the Array methods), which is the crucial difference between this proposal and the other methods that we currently have. As a matter of fact, I'd think that some of the proposals that have been mostly accepted are unnecessary as well, but classes are such a significant departure that I'd ought to think that this should be reconsidered.

In what way is it such a "significant departure"? It's pretty much the officialisation of the following pattern: function C(){} C.prototype = { method(){} } It does feel too far away from what people write and what's in the language.

Also, I hope you're aware you don't have to use the new features. And the "but people will use these feature" cannot work, because people have been writing class libraries for some time and CoffeeScript, Dart, TypeScript have classes too and people use them, so you'll have to deal with it at some point anyway.

# Brendan Eich (12 years ago)

[Fixing empty subject.]

Chris Ryan wrote:

Do we need classes at all? In my opinion, given that the concept is implemented in a clear manner and it is possible to be powerful enough to be of use in favour of prototyping (and developing based on the prototypal concept instead), then yes, it would have my support. However, my major gripe with the current classes proposal (and in fact with a few other proposals too, but that's a different story) is that it's just syntactic sugar added for the sake of it - it doesn't add any sort of functionality that cannot be implemented another way with the current toolset, and this contraption will only add complexity and confusion to the language.

No. Complexity would come from adding new kernel semantics (what's left when you boil away all the non-primitive forms). Yet you accuse us of doing anything but adding new kernel semantics ("it's just syntactic sugar"), so you're selling a contradiction here.

As for "confusion", manually implementing |super| and getting it right is a confusing and error-prone process. In fact |super| is a case of a (small) extension to kernel semantics in ES6, but this tiny under-the-hood complexity produces a net savings by eliminating the greater user-facing complexity inherent in hand-coding |super|.

Anyone who thinks |class| came from Java is not paying attention. Python, Ruby, and other languages (such as CoffeeScript, inspired by Ruby and JS with a bit of Python) have |class|, but they are dynamic. What's in a name? It depends, I think, on what you were taught.

I get the sinking feeling that someone has had a bad time drinking too much Java or C# OOP-booze and, in the manner of a reformed drunk, wants us all to do things the hard way when making prototypal inheritance patterns with constructors, static and prototype methods, |super|-done-by-hand, etc.

I observe that many other JS hackers have no such negative hangover-like reaction, and on the contrary say they could use a little sugar, and even a bit of the strong stuff (e.g., small kernel extensions such as |super|) in the punch.

# Eric Elliott (12 years ago)

Brendan,

You seem to only be replying to the most recent comment in this thread, and not considering the objections that I raised at the beginning of the thread. My argument is that class isn't just a little bit of sugar. I believe that counter to its goal, it will reduce programmer productivity by causing code arthritis, duplication, and forcing refactors that would not be needed if people instead leaned on mixins, functional inheritance, and other compositional patterns that are already easy to implement in JavaScript.

I further argue that a programming language has a UX, and good UX design should involve creating a pit of success that users fall into. It is my assertion that class is a pit of dispair, that so frequently leads people down the path of wrong design that is hard to fix down the road, it should not exist in the language at all.

"I get the sinking feeling that someone has had a bad time drinking too much Java or C# OOP-booze and, in the manner of a reformed drunk, wants us all to do things the hard way when making prototypal inheritance patterns with constructors, static and prototype methods, |super|-done-by-hand, etc."

I don't want people to do things the hard way. I want us to give people easier ways to use patterns that are less likely to lead people down the path of poor OO design. I go into much more detail about the perils of class in this Fluent talk: vimeo.com/69255635

All of those perils exist in the current ES6 class spec, not just the way it's done in Java or C#. Yeah, I had a bad time with Java and C++ in the 90's, but I've been programming JavaScript web applications since the late 90's, and having a really good time of it, until popular libraries started incorporating class-like patterns. I got over my Java hangover more than ten years ago. The headache I have now is caused by people mimicking class-like constructs in JavaScript, very similar to what ES6 intends to do.

Backbone making .extend() essentially a required mechanism has been particularly problematic in several different code bases that I have been involved in.

Unfortunately, the problem is that requirements change over the lifespan of an application, and what start out as simple models frequently evolve into complex models, where single-parent hierarchies fail. Eventually, all single-parent hierarchies are wrong for new uses.

I know that JavaScript doesn't lose its dynamic nature when we add class, but, to bring back an earlier example, say you start with:

Animal

  • Walking
    • Human
    • Ape
  • Flying
    • Bird
    • Bee
  • Swimming
    • Fish
    • Whale

Now you need alligator and duck. Alligator clearly needs walking and swimming, so you go to re-implement them as mixins, but now you have to refactor all the animals that already rely on those features -- or you end up reimplementing the functionality as mixins, and now you have the same features in two different places -- a violation of DRY. This is the duplication by necessity problem.

You have to refactor everything, or live with a design that is overly complicated and error prone.

"I observe that many other JS hackers have no such negative hangover-like reaction, and on the contrary say they could use a little sugar, and even a bit of the strong stuff (e.g., small kernel extensions such as |super|) in the punch."

It is my assertion that those same hackers would have an easier time if we'd just give them better ways to work with prototypes, mixins, and functional inheritance. For an example in code, see Stampit: dilvie/stampit

More reading on the perils of class:

davidwalsh.name/javascript-objects (three part blog post by Kyle Simpson)

en.wikipedia.org/wiki/Call_super - Super is a code smell

The gorilla/banana problem

"The problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle." - Joe Armstrong

This is a great description from "Design Patterns" (GoF) -

"Once the software has reached adolescence and is put into service, its evolution is governed by two conflicting needs: (1) the software must satisfy more requirements, and (2), the software must be more reusable. New requirements usually add new classes and operations and perhaps whole class hierarchies. The software goes through an expansionary phase to meet new requirements. This can't continue for long, however. Evuntually the software will become too inflexible and athritic for further change. The class hierarchies will no longer match any problem domain. Instead they'll reflect many problem domains, and classes will define many unrelated operations and instance variables."

This never happened to me in JavaScript until I worked in code that used things like John Resig's Simple Class Inheritance, and Backbone's .extend(), rather late in my JavaScript career. But of course, we were using objects and inheriting functionality long before those came along -- we were just using the simple patterns that already existed in JavaScript, simple single-parent prototypes, module-pattern style modules, and dynamic object extension (copying properties from one object to another).

No, my hangover is not from Java. It's from class in general -- and we're about to share that hangover with a whole lot of developers who could have easily avoided it otherwise.

When you put prototypes in JS, and made objects extensible at run-time, you did something remarkable. You made classical inheritance obsolete by bringing these ideas to the mainstream. Now you're arguing to take a step backwards. I say, let it die. It's had a long life. It's time to let it go.

# Eric Elliott (12 years ago)

"JS is a rich language that allows different styles of programming. Nothing wrong with that."

What's wrong is that when we give people class and extends, books and blog posts everywhere will begin to teach that this is how we do inheritance in JavaScript, ignoring all the perils that go with them. The default style will be a style that frequently leads developers down the wrong path.

It is a pit of dispair, rather than a pit of success. www.codinghorror.com/blog/2007/08/falling-into-the-pit-of-success.html

In contrast, we could give developers better sugar around mixins, prototypes, and functional inheritance, giving them the same ease-of-use that exists with the class keyword, without the dangers.

# Eric Elliott (12 years ago)

"I don’t think you appreciate how hard it was to reach the consensus for ECMAScript 6 classes (lots of incredibly long, incredibly passionate discussions!)"

I do appreciate it, and I bit my tongue for much of it, but as the idea of class in JavaScript has been catching on more in the last couple of years, I'm starting to see the effects of that mental shift more and more in real world code-bases, and the problems I thought I left in Java land more than a decade ago are haunting me every day again in the workplace. The more my coworkers ask about how to get around these problems, the more I'm convinced that class in JavaScript is a really bad idea.

I understand that a lot of people have invested in it, but the number of people who invested time in the design of the JavaScript language pales in comparison to the number of people who will use it. And that's what motivates me to speak out about it.

# Axel Rauschmayer (12 years ago)

I know that JavaScript doesn't lose its dynamic nature when we add class, but, to bring back an earlier example, say you start with:

Animal

  • Walking
    • Human
    • Ape
  • Flying
    • Bird
    • Bee
  • Swimming
    • Fish
    • Whale

Now you need alligator and duck. Alligator clearly needs walking and swimming, so you go to re-implement them as mixins, but now you have to refactor all the animals that already rely on those features -- or you end up reimplementing the functionality as mixins, and now you have the same features in two different places -- a violation of DRY. This is the duplication by necessity problem.

Honest question: how can this problem not be solved via ES6 classes plus mixins? The original hierarchy already feels wrong. Why not create a super-class Animal, with sub-classes Human, Ape, Bird, Bee, Fish, Whale plus the mixins Walking, Flying, Swimming?

You have to refactor everything, or live with a design that is overly complicated and error prone.

I also don’t see why refactoring is such a bad thing: as your knowledge of the problem domain increases, the structure of your program evolves. Tool support for automated refactorings will improve (partially helped by classes). Additionally, unit tests minimize the risks of refactoring.

Axel

# Eric Elliott (12 years ago)

"Honest question: how can this problem not be solved via ES6 classes plus mixins? The original hierarchy already feels wrong. Why not create a super-class Animal, with sub-classes Human, Ape, Bird, Bee, Fish, Whale plus the mixins Walking, Flying, Swimming?"

I completely agree with you, but in the real world we don't always have the benefit of knowing future requirements enough to create the correct design from the outset. Maybe the design was correct in the beginning (immagine a classification of species, instead of a classification of species capabilities)... and that's the problem with class - "so you go to re-implement them as mixins, but now you have to refactor all the animals that already rely on those features"

"I also don’t see why refactoring is such a bad thing: as your knowledge of the problem domain increases, the structure of your program evolves."

Small refactors are not a bad thing, but class hierarchies create tight coupling between child and parent classes (yes, even ES6 class, especially with super). In these situations, the dependencies are not always obvious, or direct, and they tend to ripple out far and wide, and are not easily aided by technology -- it's not a matter of replacing some variable names across your project -- it's a matter of reengineering these to deal with systemic changes in behavior.

Mixins and other compositional reuse patterns don't create any tight coupling between child and parents, and much more easily provide for selective inheritance (I only want the banana, not the gorilla, banana, and entire jungle).

# Axel Rauschmayer (12 years ago)

To me, single inheritance has always been the skeleton on which I hang multiply inherited pieces. That skeleton doesn’t even have to be a hierarchy, it could be a set of classes. Maybe you simply need to write a mixin or trait library that works well with ES6 classes?

Axel

# Eric Elliott (12 years ago)

"That skeleton doesn’t even have to be a hierarchy, it could be a set of classes."

Then you don't need extends or super.

# Dmitry Soshnikov (12 years ago)

On Sun, Jun 30, 2013 at 10:41 AM, Brendan Eich <brendan at mozilla.com> wrote:

[Fixing empty subject.]

Chris Ryan wrote:

Do we need classes at all? In my opinion, given that the concept is implemented in a clear manner and it is possible to be powerful enough to be of use in favour of prototyping (and developing based on the prototypal concept instead), then yes, it would have my support. However, my major gripe with the current classes proposal (and in fact with a few other proposals too, but that's a different story) is that it's just syntactic sugar added for the sake of it - it doesn't add any sort of functionality that cannot be implemented another way with the current toolset, and this contraption will only add complexity and confusion to the language.

Anyone who thinks |class| came from Java is not paying attention. Python, Ruby, and other languages (such as CoffeeScript, inspired by Ruby and JS with a bit of Python) have |class|, but they are dynamic. What's in a name? It depends, I think, on what you were taught.

Exactly. In fact, JS has classes for years (w/o sugar), as well as Python is prototype/delegation-based (w/ classes sugar).

From this perspective, classes themselves can be classified (long time ago

I created this quick cheat sheet for that: gist.github.com/DmitrySoshnikov/977034; became a bit lazy at that time for a full article for this, although had written before a good long analysis explaining why JS being different, "is not that different", and can be considered as class-based, as well as Python/Ruby are delegation-based. Interested may find it on my site).

A class is just a code reuse pattern, the pattern has pros and cons. A class is not the "class" keyword in a language. And even not the ability to create classes using this keyword. And even not the static shapes of created instances (see the "static second-class classes" as Java's). It's just the ability to code in a classified code reuse: i.e. create instances by the template. And this ability was here for years with "constructor+prototype" pair. This spec will only add a bit of sugar. The same as in Python which is considered as a class-based.

An important note: this sugar (and exactly the "sugar" as a slang definition for abstraction matters) will give the ability for newcomers not even know about the prototypes (and it's good). Which in this case will just become as an "implementation detail".

P.S.: although, that mentioned, this topic is better discussed on JS forums.

Dmitry