By the time it happens, it won't actually mean anything because something else, something equally despised and impure will have taken its place.
Perhaps a better question might be why are such languages more popular than their more ideologically pure cousins? What need are they filling that "better" languages cannot? Be careful if your answer is "they're beginner's tools for mediocre programmers" -- the JS community is home to some extremely talented programmers who are all there by choice alone.
The JS community is not an argument for JS I feel, because it does not have a track record of providing reliable software. Most libraries are new and a lot of devs are very lax with security or code robustness. If you use a library/tool you're not sure what you're getting - see the semicolon situation or the npm directory deletion.
This scope trick (and really, the whole JS language situation) always reminded me of the "closures vs. objects" koan:
http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/m...
var mariner= {};
mariner.new = function(){
var self = {};
var maxhp = 200;
var hp = maxhp;
self.heal = function(deltahp) {
if (hp + deltahp < maxhp){
hp = hp + deltahp;
} else {
hp = maxhp;
}
}
self.sethp = function(newhp) {
if (newhp < maxhp){
hp = newhp;
} else {
hp = maxhp;
}
}
self.gethp = function(){
return hp;
}
return self;
}
var m1 = mariner.new();
m1.sethp(100);
m1.heal(13);
alert(m1.gethp());
(shamelessly stolen from http://lua-users.org/wiki/ObjectOrientationClosureApproach)That has a pretty simple answer, it's because it was the only language available in the browser (and no, Java applets never really took off).
Had it been Ruby (unlikely given the timeline) or Python or even Perl instead, the situation would probably be much better today.
There are plenty of reasons to use JS, like "I already know it" if you're a front-end dev, "It's our only option on the client-side and using the same language everywhere is a good idea", or "V8 is heavily optimized so I can not care about performance and usually my code will run fast enough."
Actually that last one is nice. If you don't do anything too stupid, and break up work into lots of little pieces that are called exactly when they're needed, and share as little state as possible, your code runs /much/ faster and is much easier to reason about. node.js gives you those last two properties by default.
Perhaps "JS is inordinately popular for how bad of a language it is", and "Only erlang has the same concurrency model" are related. You can write something that runs as fast in another language or environment, but you won't be able to write it nearly as easily.
They have nearly nothing in common.
JS uses callback-based stuff, cooperative scheduling, and has a single process to drive everything.
Erlang has message-passing to mailboxes, preemptive scheduling, and many fully isolated processes.
Cooperative vs. preemptive scheduling is only about whether you trust the coroutines to do the right thing. Erlang cares about recovering from errors so it must be preemptive. Node.js trusts the programmer so it uses a much simpler cooperative scheduler. This does not change the concurrency model though, only the assumptions of the environment.
Erlang is (in my opinion at least) better than node.js, and also has the advantage being able to enforce no-shared-memory between actors, so it automatically distributes erlang processes across all your cpu cores. Node.js requires that you spawn child processes yourself if you wish to take advantage of multiple cores, but ones they're spawned the way you handle concurrency doesn't change.
I don't know about you, but mailboxes and callbacks look pretty close to the same thing to me. In both, your code waits for an event to happen and then reacts to that event, potentially sending off more events. In both, once you do anything that would require blocking, your coroutine lets others run while it's waiting.
The erlang model certainly has more power but they're more similar to each other than they are to anything else. The way you think is the same, although the way you write it might be a little different.
For example, an overloaded Erlang node will favour the processes that are being swamped over the other ones in an attempt to try and rebalance things. This is especially efficient during short overload bursts. Cooperative scheduling cannot explicitly do the same, or give any indication of how frequently or how much work you want to let a work unit do.
Regarding mailboxes and continuations through callbacks, not exactly. One difference is that Erlang has selective receives, whereas callbacks will be handled no matter what. This means that in Erlang, I can choose to only care about a subset of the possible events and leave the rest for later, waiting and blocking my execution until I get the right circumstances. In callback-based code, I have to think of all possibilities because callbacks can't block.
This is to say the event matrix of callback-based code will need to consider all options, while Erlang's will only need to handle a restrictive subset of them. Ulf Wiger gave a full talk on it, which is summarized here: http://dm3.github.com/2010/08/01/death-by-accidental-complex...
This also impacts how easy to maintain code, reason about it, model it, etc. You don't have to think the same because you don't have to consider nearly as many possibilities, event interleavings, or worrying about blocking stuff and killing your application (an irresponsive app is as good as dead) because of it.
And I'm not even getting into the need of callback-based code to break everything into continuations.
I've used Node.js to good effect. It's a nice piece of software for a whole lot of reasons, but I think Go proves that there is a better way: http://golang.org/doc/effective_go.html#goroutines
A couple weeks ago I was writing a php script, and it actually felt awkward to query a database and then do something "immediately" after with the result.
It isn't terrible, it's just different. And if you aren't used to it, it'll feel weird at first. This goes away with exposure and experience.
My main takeaway is, unless I absolutely have to use async code I won't. It's almost never cleaner than queuing onto a thread-pool.
In the case of highly parallel IO, yes, a thousand times yes async is great. But the great lie about node is that people need to carry over the async from the IO layer to the app logic layer. In node it's all just mashed together.
For instance, the problem a websocket server is trying to solve is multiplexing M connections onto N available cores. Async works great for the connections layer, and a thread-pool well for the logic layer.
The trick about async is that your server can handle 10,000 connections that are idle, but only a handful active at a given time since you only have a few cores. Thread scheduling works just fine.
None of these ideas are novel, in fact, they are decades old. The real problem is the faddishness of ideas.
JS, like most languages, is good at certain things, not at others. The edge cases are unfortunate but functionality can be augmented by libraries. Given the momentum behind JavaScript it's fairly likely that these edge cases will disappear in the long term.
Let us not single out JS specifically as a 'special kind of delusion'. We've all seen 'delusion' in every, single, programming, language, flamewar, on the internet. Seriously.
Everything is a tool, and you choose the right tool for the job. JS adds to the discussion.
If your trying to push JS as a tool to rule them all, that is, thee tool that _must_ do it all well, that is delusional. You'll be prematurely optimizing while(true).
Your not saying that? Then why critique it as if you were?
* while there are blocking calls in node, they are by far the exception. It is not multi-paradigm like Java
edit: To expand, the alternative is to fire off threads for each connection so you can write 'synchronous' code... the whole point of nginx and node is so that you don't need the overhead of creating a separate thread for each connection, asynchronous code is the natural result of this decision.
Can you explain the integer math thing? What exactly can't it do?
$ python
Python 2.7.2 (default, Jun 20 2012, 16:23:33)
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> x = 1000000000000000001
>>> x
1000000000000000001
>>> x == x + 1
False
$ irb
irb(main):001:0> x = 1000000000000000001
1000000000000000001
irb(main):002:0> x == x + 1
false
$ clj
Clojure 1.4.0
user=> (def x 1000000000000000001)
#'user/x
user=> x
1000000000000000001
user=> (= (inc x) x)
false
$ node
> x = 1000000000000000001
1000000000000000000
> x === x + 1
trueIf you're dancing on the edge of the limits of numerical representation then you need to write code to protect against bad things. If you don't write said code, your program is going to fail to work correctly, no matter what language you use.
>>> int('0x7fffffff', 16)
2147483647
>>> int('0x7fffffff', 16) + 1
2147483648LI'm curious as to why this discounts a tool meant for performing IO and various web development tasks in general.
Has anyone run into a integer math related issue when using node (that was a deal-breaker)?
[0] http://stackoverflow.com/questions/8663298/json-transfer-of-...
[1] http://stackoverflow.com/questions/6320908/twitter-json-in-r...
[2] http://stackoverflow.com/questions/209869/what-is-the-accept...
The fact of the matter is that JS is bad at all the things a programming language is supposed to be good at. JS can't even perform integer math. It's also fairly alone in being async by default (and no, comparisons to erlang do not count).
Does JS work? Sure, but believing JS is good is a special kind of delusion. We have decades of language research to work with, and once again we see the pull of the lowest common denominator.