back
60 comments
This seems rather un-self-aware. Yes, "class Food { etc. }" feels more intuitive to you than how it works in JS because you learned on the classical inheritance pattern. But classical inheritance is not fundamentally easier to understand than prototypical inheritance. You've just used it for so long that you don't remember what it was like to see it as a newcomer.

If you want to be fair, this should be called "the problem with OO programming", and the summary of the problem is that it's complicated and requires that you learn a lot of counterintuitive concepts.

The problem with Javascript's prototype system is that it's not a real prototype system - it's a chimera that's halfway between a traditional prototype system like Self and a class system like Java.

The result is a system that is fit for neither paradigm. Trying to do work in either one requires a lot of extremely counter-intuitive lines of code that 'you just have to learn'. Unless you want your code to get bogged down such lines, you end up using libraries that allow you to write something that looks more like either Self or Java.

So, the problem isn't that people haven't bothered to learn 'the right way' to do protoclasses in Javascript. The problem is that 'the right way' is stupid. Either make a real prototype system or a real class system (or both!). But the reason that everyone is so unhappy with the state of things is because it sucks.

The trouble goes deeper than that. Prototypal inheritance in itself probably wouldn't be all that confusing for these people — it's actually a simpler concept than classical inheritance. The issue with JavaScript's object system is that it's downright convoluted.

AFAIK, Self is the progenitor of prototype-based OO. In Self, the way you create a new object is just `someObject copy`. You can dynamically change its prototype later if you want, too. But in traditional JavaScript, you can't do that. You want an object? You need a constructor. Instead of just cloning a prototype, you have to do the whole `function Foo() { blah blah.prototype = someObject blah blah }; myFoo = new Foo()` rigamarole, and there is no standard way to access an object's prototype.

JavaScript has finally got the equivalent of Self's object creation with Object.create, but that is pretty new — and the actual object system still has the whole wonky prototype/constructor/__proto__ mess behind the scenes.

Object.create doesn't have the constructor bit at all. Try for yourself, create an object from another using Object.create and see if the second is an instanceof the first (it's not).
To be fair, the list of issues are what someone from an OO background will eventually run into when using JavaScript, and the article does offer solutions to those issues for people who want them fixed (namely cross-compilation, or models for dealing with small or large projects).

That said, people using JavaScript should be playing to JavaScript's strengths, or picking a different (if not cross-compiled) platform. It's bizarre that people from fundamentally different programming backgrounds complain about these issues. If you don't like C, don't use C. If you don't like JavaScript, write a native application, or cross-compile. There are options, they're in heavy deployment on several major websites, use them. Then everyone can pick the platform they're most comfortable with.

I've started programming in JavaScript before or at the same time I started programming in Java and still find that the author's argument is mostly valid. It's not a matter of habit, it's a matter of consequences and the amount of knowledge you need to have to make basic language features work correctly.

Prototypes are simply more complicated than classes. They change behavior of objects, whereas classes _define_ behavior of objects. The syntax doesn't help it either.

That's your opinion. My opinion is that prototypes are simpler than classes. The distinction between a class and an object can be very tricky, especially once you get dynamic or introspective because then you run into the situation where classes are also objects.
> Prototypes are simply more complicated than classes.

[citation needed]

I'd argue the opposite: "Prototypes are simply more _intuitive_ than classes."

OO-design says that X is-a Y is-a Z, with inheritance providing the main form of structure.

Prototypical-design says that X is-like-a Y, but with these differences. This NPC (specific, X) is like any other NPC (general, perhaps the original NPC prototype), but with the name Fred and this custom AI code.

They're different ways of thinking, but prototypes are certainly not more complicated than classes in the general case.

----

As for the syntax, though, I totally agree with you.

> Prototypes are simply more complicated than classes.

Only if you try to make them act like classes.

I mostly agree, but it has always struck me as bizarre that to define something like a "class" you wind up defining a function. Sure, that function works like a constructor together with new(), but even after all these years, it still strikes me as a bizarre language choice.
Well, the problem is that you're trying to bring analogies over from classical inheritance that don't directly apply. We're trained in classical languages to think of classes as being these blueprints in a strange hierarchy of blueprints and a "constructor" is this weird method by which a class transmutes itself from the abstract to the corporeal, producing an "instance".

In prototype-based OO, a constructor is just a function that builds an object. If you like, you can give that function a starting point for building its objects (the prototype), but in the end, it's just a function that builds an object. It's conceptually not that similar to a class in classical OO, even though you can use it to implement classical inheritance.

And that's really the core of the problem: read any book about JavaScript, and the first thing they'll probably tell you after introducing prototypes is how to get something like classical inheritance hierarchies by chaining prototypes together. So people end up thinking "what a strange and roundabout way to handle classes", when the problem is that they shouldn't be thinking about classes in the first place.

And here's the elephant in the room: long prototype chains are not usually the right solution because long inheritance chains in general are not usually the right solution. Classical inheritance just makes it so easy to build elaborate and beautiful hierarchies that most people never realize that doing so is usually just adding complexity for no real gain.

>This seems rather un-self-aware. Yes, "class Food { etc. }" feels more intuitive to you than how it works in JS because you learned on the classical inheritance pattern. But classical inheritance is not fundamentally easier to understand than prototypical inheritance.

Classical inheritance IS easier to understand compared to how prototypical inheritance was implemented in Javascript --and it's obvious from the examples he gives, and all the workarounds to use prototypical inheritance correctly in all the major JS frameworks.

The implementation details of prototype inheritance should not leak to the language, but in JS, they do.

I would argue that the biggest issues with JavaScript are:

- Most obvious solutions to simple problems are often wrong. (Examples: iterating over a "dictionary", getting a variadic function to work.)

- Callbacks that create callbacks and so on (hard to understand the real structure of the program) and callbacks that are shoved into global variables (hard to debug).

- Insane type conversion paired with poor error logging. (This has nothing to do with being dynamically typed, BTW. You can be dynamically strongly typed or at least have some safeguards.)

I'd add that it's too easy to pollute the global scope accidentally, because a simple anonymous block structure (e.g. braces) to scope variables is not allowed. Best workaround is to wrap most all code in an anonymous function that is then immediately executed (function() {<your code here}}).(), but that's ugly and easy to forget. I think Coffeescript does this by default for all blocks of code, which IMO is one of the principal reasons for preferring it to original javascript.
As an ex-Actionscript, now-JS programmer a lot of this resonates with me.

After the move, I missed a lot of things - mostly the productivity stuff like type-safe renaming; intellisense; clickable function names. Also the presence of a real module system, and the fact that the compiler would catch my typos.

However, after comparing my two codebases (the original one in Actionscript and the new on in Javascript), I can't help but be amazed at all the damn boilerplate that's in my Actionscript. I ended up spending an enormous amount of time specifying interfaces and careful inheritance chains so that all of my type annotations would be compatible and safe. Did I need to do all that? Probably not, but the design of the language certainly encouraged me to do so. I can't help but wonder what I could have done with that time - especially considering the fact that my JS codebase doesn't seem to have more bugs or worse stability.

Would I switch back if I could? I'm not sure.

I can't help but think that there's a real opportunity for a Coffeescript-like language with a module system, clean class syntax, and some Go-like features such as Go interfaces and type inference, plus manual type annotations when necessary.

"I can't help but think that there's a real opportunity for a Coffeescript-like language with a module system, clean class syntax, and some Go-like features such as Go interfaces and type inference, plus manual type annotations when necessary."

haxe meets a lot of these criteria and has been around for a while.

Usually rants on Javascript pound on the warts it acquired due to being rushed to production back in 1995. Warts like semicolon insertion, the lack of a module system, etc.

Instead of that, we get boring syntax arguments that seem to have come from yet another static vs dynamic programming language flame war, written by some someone that thinks the Java OO model is the only acceptable OO model. More then half that list also apply to Python or Ruby and that is just silly.

I wouldn't exactly say that the list is wrong, just because half of it also applies to Python or Ruby. All languages have some kind of issues, so I guess it's an okayish list of Javascript specific gotchas.
Random contextual side note:

Colin Moock has been contributing to the webdev world since the late 90s (http://www.moock.org/webdesign/) mostly focused on Actionscript. Back when people thought web development was a joke (and not flash), he did a ton of work teaching and writing about what he had learned and I probably wouldn't know what I know about web dev without folks like him.

That being said, I think the lecture was poorly titled given his conclusions...

I thought the same thing since I've followed Colin since starting Flash development. It turns out the title of this post is incomplete, on his lectures page it is actually "the trouble with javascript (and why it's worth it)" http://www.moock.org/lectures/
Here's why a "class" definition is a "function" in JavaScript:

Since JavaScript is prototypal and not class-based, the "new" operator simply creates a tabla rasa object. The argument to new is a function that runs on the new object with "this" in the scope set to the object.

Thus "new foo()" creates an blank object and runs foo on it. You can do this with any function!

If you don't try to force C++/Java semantics onto JS, it's much easier to understand.

"The trouble with JavaScript is that when I try to pretend it uses classical inheritance, nothing works the way I think it should."
I find it a little worrying that "Must run every line of code to find all the errors" made the list. More worrying was the fact that the author thought having compiler-enforced type safety would relax that requirement. Giving the benefit of the doubt, maybe by find all errors, he meant "find all type errors except for anytime anyone does something dynamic or a cast".

I would hope we all recognize by now that even running all lines of code (100% test coverage) is insufficient to find all errors (especially semantic ones). In any language.

The title is incomplete, on his lectures page it is titled "the trouble with javascript (and why it's worth it)"

http://www.moock.org/lectures/

Are there really no JavaScript-capable IDEs out there that support code completion, jump to definition, re-factoring, etc? I don't see anything in the language that would preclude such features.
Yes there is, and it works quite well: http://www.jetbrains.com/editors/javascript_editor.jsp?ide=i...

For sure it has some oddities with the completion as it can't be sure what the prototypes are, but then it just lists functions from different prototypes which match your prefix.

  function DoStuff(foo)  //<<<<No information what type foo is
  {
    foo.DoA();  //No way to know what methods foo support
    foo.DoB();
  }
For most situations where it is possible to infer the type, Visual studio actually does a pretty good job on code completion, but no jump to definition.
WebStorm has jump to definition, re-factoring, code inspection that provides valuable auto-complete suggestions (and if you use JSDoc tags it can read those) and more: http://www.jetbrains.com/webstorm/features/index.html
"Would YOU Let JavaScript Land Your Plane?"

No I wouldn't, but I'd let it run my web app. Dude it's javascript, it runs in a browser! What other language runs in all the four major browsers? None.

I actually would definitely let JavaScript land my plane, assuming it had undergone substantial code review, had exceptional test coverage, and was interfacing with a reliable and sane API (I would definitely not let the DOM land my plane). In other words, under the same conditions as I would want for any other language.
This just in: Javascript does not follow the One Way to do things. Developer outraged!
The trouble with JavaScript is the name is misleading - you're lead to believe it's a scripting form of Java. Instead it's more akin to Lisp in C clothing. Doug Crockford explains it best. http://www.crockford.com/javascript/javascript.html
If all you want is classical inheritance, there are so many libraries that are available which mimic that.
I would say "or just use CoffeeScript", but you really should understand JavaScript better than that before using CoffeeScript.
Most of the author's 'trouble' would be solved by reading "Javascript: The Good Parts"
I came here to post exactly this. I don't know what's happening, maybe it has always happened, but these days I get more easily pissed when someone's trouble could be solved just by reading a book... People: blog posts are nice and all, but for god sake, just read a book. Especially when there is a good, almost universally agreed upon, such book.

I think it's unbelievable that people want to learn about a subject but can't be bothered to read a book about it. This leads to flawed learning at the foundational level, and then avoidable surprises when years (yes, years...) down the road people discover some "unexpected" behavior they should have learned about at the very beginning of the learning journey.

In ye good olden days, when people came to a forum with a stupid question that could be easily solved if the person asking would just bother to read the manual, they used to get a polite RTFM...

Maybe we should start saying RAFB when stuff like that is posted.

Let me guess.. you are a java senior developer, aren't you? You should learn python, or ruby. They will open your mind to a whole new level of abstraction.
Please. Python is my favourite language, and has hardly any of the silliness of js. In python classes are still classes, methods are still methods, constructors do look like methods but are clearly a special method. Calling something from the superclass looks slightly odd, but only slightly. People know better than to monkey with object internals unless they have a good reason, in a way that doesn't seem to happen in javascript - I suspect because many perfectly sensible things in javascript look like monkeying around with object internals (foo.prototype.x = ...). Python is dynamically typed, but it gets away with it because its types are strict; if you think a is an int but it's actually a string, you'll catch it when you try and do a + 5. And even given that, python has added (weak, optional, but still there and standardized) type annotations. Code completion works, I don't know how but it does (maybe this could be done with javascript too). Modules are standard and heavily used. The language has a standard and multiple compatible implementations.

Thought: if "prototypal inheritance" really is more powerful/useful/etc., why don't we see efforts to implement it in languages with traditional classes? I've seen dozens of attempts at implementing "traditional" inheritance in javascript, but none goingin the other direction.

I've only dabbled in Python, Ruby and JS, but when I sat down to actually write node.js code, I felt like I was writing (basic) Python with C syntax. Given that I've more-than-dabbled with C... :)
Don't get me wrong, JavaScript is horrible. But an argument whose major point is JS' OO is a joke is kind of weak. You would be better off thinking of it as a C-syntaxed functional programming language with mutable data structures.

Not that it's a more accurate description, but trying to use it as such will make you more productive and make you write better code.

Did he just complain that there are no compiler errors in a interpreted language?
He basically said 'it's a prototype-based language, therefore it is bad.'

...

so? Javascript is never, ever going away.

It'd be real nice if ECMA made some changes to fix the ugly, but how long would that take to propogate? A decade?

... and your point is?