The trouble with Javascript
moock.org
moock.org
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.
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.
No, that's an objective statement, on which the creator of the language and some of the greater gurus of it, agree.
>My opinion is that prototypes are simpler than classes.
Not in the way prototypes are implemented in JS.
The creator of the language was apologized lots of times for it's many warts (due to lack of design and time constraints plus limited initial scope for the language), and the greatest of its' gurus had to write a book called "Javascript, THE GOOD PARTS".
Someone who cannot see the flows of Javascript's implementation of prototype inheritance, seriously cannot assess good and bad software design.
Secondly, you appear to be claiming that Crockford offers strong criticism of JS's inheritance model in The Good Parts. If that's what you took away from it, I think you would do well to reread that chapter.
Of course JS's inheritance system is imperfect just like that of pretty much any other language.
Well, he sure is on a very short list of js programmers. Who other can you add? Maybe Resig? Ashkenas?
>Secondly, you appear to be claiming that Crockford offers strong criticism of JS's inheritance model in The Good Parts. If that's what you took away from it, I think you would do well to reread that chapter.
No, I'm saying that Crockford doesn't like the way prototypal inheritance is implemented/exposed in javascript --not that prototypal inheritance is inherently bad. He even writes that the basic action of getting prototypal inheritance is not first-class in js:
"In a prototypal system, objects inherit from objects. JavaScript, however, lacks an operator that performs that operation."
And in order to use prototypal inheritance he has written a wrapper function to hide all the inheritance boilerplace correctly. (As has every other js programmer I know of, using several patterns).
Only if you try to make them act like 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.
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.
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.
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.
Isn't this called pseudo-classical inheritance?In purely prototypical inheritance one object inherits from another object, there is no need for constructors whatsoever, instead you are just setting __proto__ link so that it points to the object from which you want to inherit.
This way you have much more freedom - you could add initializer method that sets up variables in a similar fashion to constructor, but you could also easily implement singleton or mixin patterns.
Ideally, prototypical inheritance would be done like in the code below, but I doubt we will ever see this supported by JS:
obj1 = {
__proto__: Object.prototype,
init: function() {
}
}
obj2 = {
__proto__: obj1,
init: function() {
super.init()
}
}
obj3 = {}
obj3.__proto__ = obj2
obj3.init()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.
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.
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.)
It's a nice feature, but saying it's one of the principle reasons to prefer CS over JS is a stretch. Wrapping your entire file in an IIFE is a one-time development cost and a simple pattern to remember. Compare that to the syntactic sugar, safeguards, and added functionality that one will leverage constantly during development.
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.
Also, a new version of the haxe compiler was just released that is geared towards supporting new js features and cleaner integration: http://haxe.org/download
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.
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.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.
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.
class Animal
constructor: -> @type = 'Zebra'
feet: []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.
Also, classes are only classes in Python if you want to. You can do some very crazy shit if you start messing around with metaclasses :)
Another thing: there is nothing fundamentally wrong with coercing types. The only time you have an issue with this is when you combine overloading with coercion. Particularly, JavaScript overloads + and uses it to coerce values, which is just broken. Either overloading on types or coercing types by itself is fine and neither is clearly superior; the problems stem from having both.
JavaScript also has a standard and multiple compatible implementations; all the cross-browser issues I know of have to do with the DOM rather than the language itself. On top of this, some of the JavaScript implementations are really fast for a dynamic scripting language.
Also, let's not get into Python's many problems and weird semantics. It may not have the "silliness" of JavaScript, but it has plenty of silliness of its own. I say this as somebody who's been forced to use it both at work and in my courses: it's just as confusing as JavaScript was, just in different places.
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?