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.
Although the ideas and technology behind node.js aren't entirely new, the fusion of a well known client side language like Javascript and a robust server-side event based architecture really makes node.js great.
I really enjoyed the article because it approached node.js as it should have, as the new way of doing things on the server. I see node.js becoming as ubiquitous as ruby/python/perl are on the server (maybe even for desktop applications).
Even if node.js doesn't become as big as I think it will, I feel that the shift is has helped cause is a positive one for the server space and we will all benefit from it.
If you're into Node.js and Redis we (Voxer) are actually hiring engineers. We're building a Walkie Talkie for iPhone and Android. In more technical terms Voxer is a low latency messaging system for voice, images, and text.
We have an iOS client in the App Store, and an Android version is in the works. We've had explosive growth in the last couple of weeks and are now in top 25 in a bunch of app stores and we are looking for someone to help us develop the server side components and make the system scale.
Email me gustaf@voxer.com if you want to know more and I'll connect you with the right person.
Our servers are built out of Node.js, CouchDB, and Redis. If you are
excited about node, server-side JavaScript, and new databases, this is
an opportunity to work on this technology full-time.
Somehow I don't think rolling their eyes at developers discovering a need for what they have to offer will do the Erlang community any good.
If they sincerely believe that Erlang offers a superior alternative to Node for what the influx of new Node developers need, then they should be looking to provide resources to help these devs "graduate" to erlang.
Not once have I seen a blog post saying "Like Node.js? Then you're going to love Erlang! Let me show you why it's better, with some snippets to compare and contrast."
Not once have I seen a blog post saying "Like Node.js? Then you're going to love Erlang! Let me show you why it's better, with some snippets to compare and contrast."
Given the fact that there already exist bridges that can take javascript snippets and run them in sub-processes within erlang I am really surprised that no one has bothered to do a "enode" system that just provides a node-like api for the callouts to the javascript processes.
couchdb can only run javascript functions on json objects, and really only to transform those objects into other objects. last i checked, it has no way of interacting with the erlang node it's hosted on.
I like different languages but Erlang is like Lisp in that it has yet to really grab me. The difference being, Lisp has far better odds of grabbing me. As far as I can tell, Erlang's advantages can be cloned elsewhere in more pleasant to work with languages.
Could you list what you consider to be Erlang's advantages? Most of the ones that I can think of off the top of my head fall into the range of "possible to clone, but would take a huge amount of engineering effort" (e.g. OTP), or alternatively "a culture issue" (e.g. "let it crash", and the language's completely obsessive focus on application stability, both of which are pretty much diametrically opposed to the common language philosophies today).
I was thinking primarily of "let it crash" and "message passing". They don't seem particularly tied to the language. I'm not familiar enough with the OTP to comment.
I must have missed the current common language "philosophies", at least what concerns their opposition to focus on stability ... what are these? Can I avoid them?
C is not a language optimized for stability. The possibility for segfaults, buffer overflows, etc. and the lack of a sensible mechanism for handling them other than "write the program correctly" demonstrate this. It is, essentially, a language optimized for writing Unix.
Shell is not a language optimized for stability. It is optimized for interactive use, above all else - it's not even a very good scripting language, even though it's historically been used that way an awful lot.
The primary focus of Java (at the time of it's creation) was "write once, run anywhere". The primary focus of Java (now) is "languages that compile to JVM bytecode are nifty - plus, we have C-like syntax but are a high-level language".
The primary focus of Erlang, before and above anything else, is program stability. OTP exists to increase stability. "Let it crash" exists to increase stability. Parallelism and message passing are in the language not because they're neat, but because (if they are used at all sensibly) they will increase stability.
Put that way your point is more clear. You compare with languages from the last 40 years, I took some issue with "current".
Still I cannot see why this is a cultural issue that keeps developers away. Missing things like good string-libs, or ",;." syntax hassles, ok. But stability-features?
The point you address for C is , in a way, also valid for Erlang. It's your program which has to be stable, the language just offer you supervisors and independent processes. "Write it correctly" is the only way to achieve that goal, Erlang does not help you with that. Could be that messing up an OTP behaviour is as easy as dereferencing a null pointer... (disclaimer: I'm no Erlang developer)
Oh, I agree. Every time someone advocates Erlang they mention how it was used to build super-reliable telecoms and they start mentioning three-letter acronyms and immediately everyone's eyes glaze over. It just isn't sexy like node (yet?).
There are always Efene and Reia if you want sexy things. (However, I find it somehow disturbing that there are almost no documentation on Reia beyond the examples on its site's start page.)
One could compare Node.js to Twisted, Tornado or EventMachine. However, comparing Erlang to Node.js is somehow weird as they have different paradigms — Erlang is highly-concurrent with its "green" processes, while Node is single-process single-thread with "asynchronous" paradigm.
(However, there are some aspects, that could be compared. Erlang has "let it crash" motto, while in Node.js one has to be careful with any exceptions. Erlang is distributed and Node.js has no notion of processes.)
Just as this story came up I was watching the video of Ryan Dahl explaining Node.js (someone had shared this link in the recent thread about the event loop)
In it, Ryan makes an important point about JavaScript being a natural fit because it was designed for a constrained environment. In particular, there is no way of doing I/O in JavaScript's traditional browser environment without providing a callback argument (I'm not counting interacting with the DOM as I/O here, and a couple of pedantic exceptions pointed out by judofyr below), and for the way in which the browser guarantees that only one callback will be executed at a time.
I think this idea of a constrained environment is very important. If blocking I/O functions are strewn about the APIs you have at your disposal, then programmers tend to default to using them.
The other point he makes is that often evented APIs are just missing from the underlying platform. Does every way of doing some sort of I/O in the universe of Python APIs have variants that take callback arguments? Even if the answer is 'yes' (which would surprise me) there is a minefield of blocking calls one would need to avoid in a disciplined manner.
...which may not be easy. Tell me: does myAwesomeFunction() do some blocking I/O under the hood? You can't tell from the name. Do the docs always make that clear, and provide an alternative with a callback?
Edited to include judofyr's exceptions — which bolster rather than undermine the point, because note that window.prompt's raison de'etre is to block for user interaction, and document.write is a RAM operation rather than disk or network I/O.
I would hardly call window.prompt and document.write i/o since they never hit disk or network (to over-simplify). They're more like manipulating an object in memory.
For real i/o in JavaScript, look at AJAX: Callback based.
You are entirely right. In my mind use asynchronous for what it is good for, but use as little as possible. Delegate app logic to a synchronous threaded worker pool unless you absolutely cannot.
The problem with other even-driven frameworks out there is that they have too much existing codebase that is blocking, which is why Ryan Dahl went with javascript. It had no preconceptions how to do things, and didn't have a large library of modules and code that it would need to interface with that caused it to block.
Python isn't slow by any means, but I think for what they were trying to do, node.js really fit their use case better. Being able to hook up so many different types of functionality all into one 'application' is really freeing especially considering how approachable it is.
I love Node, but I don't think this is particularly true. I have had no problem writing Event-driven Perl apps that talk to web users, use ZeroMQ, talk to a SQL database, talk to Redis, read from disk, and spawn external processses... with none of those operations blocking.
Look at the AnyEvent:: namespace on search.cpan... there's a quite a bit of stuff there. Everything that Node has, and more.
You should use Node because you like Javascript, not because other languages don't have as good of libraries... because other languages have as good of libraries.
We had built an event-based server in raw Python using epoll. It was fine, and Python is a great language. In my testing with a very early version of node, I found that node was between 4 and 10 times faster than Python.
Not too long ago I've written some simple CAPTCHA service with Node.js, node-redis and node-canvas. It was a simple application that generated a word from a specific grammar, saved it to Redis for further reference and returned a PNG.
While being ridiculously fast it leaked memory like crazy. So I've found that there were almost no debugging tools (except for old good gdb) to find out what was going on. (I've heard that there are some changes like `node debug`, though. Should dig the archives and try code with latest Node version.)
I believe this was an inherent consequence of JavaScript and V8 being tailored to short-lifetime (milliseconds of DOM operations, then lazy waiting for events to fire) applications with low amount of events (user in-browser activity).
I believe this was an inherent consequence of JavaScript and V8 being tailored to short-lifetime (milliseconds of DOM operations, then lazy waiting for events to fire) applications with low amount of events (user in-browser activity).
Nope, it's just bugs. Every programming language has memory-related bugs... just less of them as they get older.
>We're still a long way from a 1.0 release. Version 0.4 arrived just last month.
If memory serves, 1.0 is not so far way... half a year? When node hits 1.0 and there is a perception of API stability, third-party development will likely explode.
Node.js is great stuff. It's not new (as far as concepts used), but really nice to work with. Javascript tools and runtimes are growing up very fast; it'll probably go on to surpass Erlang for this purpose if the libs are stable enough. Node.js was the killer framework for JS anyway.
Javascript tools and runtimes are growing up very fast; it'll probably go on to surpass Erlang for this purpose if the libs are stable enough.
I don't know whether to laugh or to cry... Node/JS may replace EventMachine/Ruby or Twisted/Python for quickly whipping up an evented app or service, but it will be quite a while before anyone would consider moving an erlang project to node. Node is little threat to the distributed, fault-tolerant, concurrent niche that Erlang occupies -- within that realm there is nothing you can do in node that can't be done better in erlang and a great deal of bulletproof infrastructure in the frameworks built up around erlang and its vm that node will never come close to.
I agree with you, I should've phrased that differently. What I meant to say is that a lot of people using it will use it for something which would be better served using Erlang and this will definitely get worse when the tools and runtime improve. If you are using Erlang already , you will probably never move, but if you are new to it, you will be tempted to use Node.js instead, even though Erlang might be a better fit. That's what I meant; sorry for not stating that more clearly.
What he says is basically true. Node is never going to replace Erlang for the same reasons it will never replace C++. Erlang is simply different from Javascript and no amount of runtime improvement can change that.
Not sure what "replace" and "threat to erlang" means, but: for shops that already run the JVM and .NET, I think many'd be inclined to look at akka (or scala actors) and asynch workflow as available today in F# (and promised for C# 5/.NET 5). But the important thing is that erlang is no static target, development is going very strongly: read the release notes for e.g. R14A, B and B-01.Ask questions on the mailing list if you're not sure what something is, they're very friendly. (maybe someday they'll fix apache not to give out direcotry listings like this ;->
It seems like event based programming would be really cumbersome in comparison to having lightweight threads ala Erlang. Perhaps Javascript needs lightweight threads?
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.