I've actually spent a lot of time with Node since the company I work for was an early adopter. This all based on opinion but, my general feeling about Node is that the underlying concept is great but, Javascript is an awful language to do it all in. The lack of real support for continuations (and/or coroutines) means there is no escape from the callback hell and tracking down errors can be a real nightmare. Ultimately for simple projects Node works fine but reach a point where your application becomes at all complex and things can get hairy real fast (of course this statement could be made about client side Javascript as well).
I say this not to discourage anyone from trying Node because for many projects Node may be just what you need but, there are some downsides one should probably keep in mind.
After reading your post I struggled to decide whether I truly believed that coroutines were better than callbacks. This HN thread provided some useful discussion for me: http://news.ycombinator.com/item?id=1549168
I still don't know enough to take sides, but the thread I just linked helped me to better understand the issue.
By coroutine, he really means a language feature that converts:
do_something_and_then(function (){
do_another_thing_and_then( function (){
say "we're done!"
});
});
to:
do_something;
do_another_thing;
say "we're done";
Coroutines are one way of doing this, but source rewriting (Haskell-"do-notation"-style) also works.
An instructive example is the Coro module for Perl (which is a bit more coroutine-ish, as it provides separate perl and C stacks for each async action, etc.): http://search.cpan.org/perldoc?Coro
It lets you write something like:
async {
my $t = AnyEvent->timer( after => 5, cb => Coro::rouse_cb );
Coro::rouse_wait();
say "OH HAI";
};
instead of:
my $t = AnyEvent->timer( after => 5, cb => sub {
say "OH HAI";
});
This may look like it's not an improvement, but it is after you add some sugar:
sub sleep($) {
my $seconds = shift;
my $cb = Coro::rouse_cb;
my $t = AnyEvent->timer( after => $seconds, cb => $cb );
}
async {
sleep 5;
say "It's been 5 seconds!";
sleep 10;
say "It's been 15 seconds!";
};
instead of:
my $t; $t = AnyEvent->timer( after => 5, cb => sub {
say "5";
$t = AnyEvent->timer( after => 10, cb => sub {
say "15";
undef $t;
});
});
I don't think one really needs to take sides one simply needs to know their tools and know that they can be dangerous if not used properly. Both sides of the coin have merits. Personal I am a big Haskell user so my views on IO should probably be disregarded.
On the contrary, as a Haskell user your views on IO should be kept in a thunk waiting for evaluation if they're ever needed. Unless you're one of those guys who've figured out how to do iteratee IO, in which case I tip my hat to you.
I am not an expert on Node. But IIRC, Dahl tried and rejected a coroutine style for Node. The problem was that context switches that may or may not happen inside of any function that you call end up creating consistency problems that are almost identical to the thread-safety issues that he was explicitly trying to avoid by creating Node.
Do you have pointers for that? That really surprises me, as the two are essentially equivalent, except that function closures as in Node introduce a new, restartable (usually an unwanted/unexpected featture) scope, and coroutines maintain the same scope.
Thread safety problems are all about data changing in between your statements due to some other threads. Coroutines make that happen only along calls to other routines, which is very disciplined.
By the way, node is built on V8. I get the impression that Ryan is not at all interested in inventing a new language. He is interested in a language that runs quickly. Anything outside of the scope of JS run on V8 inches into the "new language" designation. Basically, any syntax you couldn't use in the browser is a no-no.
I cry that node.js and JavaScript aren't simple, easy to use, and so foolproof to deploy that it would displace PHP as the go-to language for shared hosting.
mod_php is the benchmark. Until you can drop a .js script into ~/public_html/ and have it render HTML and execute the escaped PHP you won't be as simple for a beginner.
Edit: I love coffeescript - prefer it to JS when using node - but I still can't build a web app in a single file on ~/public_html on a shared webhost. Yet.
It's too late to edit my post up there, I meant to say 'render the escaped javascript'. Here's an example PHP script that works as a drop-in assuming mod_php is installed:
All a would-be programmer needs to get rocking in PHP is basic HTML knowledge (check w3schools for instance), an FTP client, and a link to the online PHP manual with its searchable index and extensive sample code. Getting to that point with Node is still a ways off.
Also, node's cb-passing stuff is pretty close to the very canonical examples of CPS in Scheme, so I'm not sure what you mean by it not having continuations.
I've actually spent a lot of time with Node since the company I work for was an early adopter. This all based on opinion but, my general feeling about Node is that the underlying concept is great but, Javascript is an awful language to do it all in. The lack of real support for continuations (and/or coroutines) means there is no escape from the callback hell and tracking down errors can be a real nightmare. Ultimately for simple projects Node works fine but reach a point where your application becomes at all complex and things can get hairy real fast (of course this statement could be made about client side Javascript as well).
I say this not to discourage anyone from trying Node because for many projects Node may be just what you need but, there are some downsides one should probably keep in mind.