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 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.
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.
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.
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.
[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.
Only if you try to make them act like classes.
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.
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.
- 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.)
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.
haxe meets a lot of these criteria and has been around for a while.
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.
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...
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.
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.
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.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 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.
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.
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.
...
Off topic, but what font is that?
It'd be real nice if ECMA made some changes to fix the ugly, but how long would that take to propogate? A decade?