Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Erlang vs node.js (dedasys.com)
32 points by davidw on April 29, 2010 | hide | past | favorite | 31 comments


What I am really waiting/hoping for is someone to take the erlang_js hooks that the Basho guys created and use them to provide a node.js interface that is actually run by erlang. The erlang side chops up the js at the various node.js API interface points and then handles everything that node.js is supposed to provide, but does it using the power of erlang to run the show. Instead of being its own event loop node.js just becomes an API that the erlang side provides for the js code.


supervisors and process hierarchy is missing from his list of things erlang does really well (he mentions fault tolerance but ties it to distributed computing). for node.js to implement the message passing/process linking that erlang has would be difficult; and it would be easy for node to then lose some of what makes it so interesting.


I was trying to list practical things - what category would you put the process stuff under? In other words: process supervisors are not really an end unto themselves, they're part of what makes Erlang good at X.


"let is crash" is critical to the erlang approach. erlang's approach to concurrency fails without it.

I recommend reading Joe Armstrong's thesis: http://www.sics.se/~joe/thesis/armstrong_thesis_2003.pdf

Your comparison of erlang and node.js is a reasonable exercise. However, I think the most valuable thing to get out of the exercise is that node is not really in competition with erlang. I think its more interesting to look at how node can be used to handle non-blocking http requests (and compare that to rails/django) and write your server code in the same language as your client side code.


There are areas where they clearly don't compete at all (phone switches come to mind), but I think that for many web/networking type things, they do compete.


The process hierarchy is a big part of what makes coding in a "let it crash" style possible, and AFAIK it's fairly unique to Erlang (though some other languages have copied it).

Pattern matching is another big part of it, but several other languages did pattern matching first.


Sure, but if you're talking at a high level, what is the "let it crash" stuff good for at a practical level? I think I'd put it under 'fault tolerance', but maybe there's another category I should add? The original poster mentions I left it out, so it'd be fair to add it, but it needs a high-level, practical label to put it under.


The first key point about 'let it crash' is that you drive towards zero-defect programming. Every time the system walks away from the happy path you crash write a log.

Every day with our production systems we check the live production logs to identify defects that we try and remove.

The second key point about 'let it crash' is that with OTP your system is always macro stable. Even if every function is only a stub and every stub contains exit(bleh) and always fails at a micro level, your system is always macro stable - the gift that keeps on giving!


Fault tolerance and declarative programming. It's easier to write code that clearly expresses your intent when you don't need to clutter it with error-handling code.

Likewise, pattern matching completely eliminates complex layering of nested 'if' statements, and is an alternative solution to the kinds of problems typically solved with polymorphic dispatch in OO languages.


Oddly enough, I just started a project that uses nodejs to access riak which is built on erlang. In addition to accessing data natively via erlang, riak speaks http and now protobuffers. Currently I have node.js speak to riak over http and I may change this in the future to use pb instead.

The one issue I have with nodejs at the moment is that since it is nonblocking, when you call riak and ask for data nodejs will move on and continue execution when what you really wanted is that the next execution use values returned by riak. The main way to do this is to chain your calls so you basically nest your next call inside your current call. This can get sloppy. Apparently there is no built in method to wait on results. There were promisses but they were removed. Now there are some add-on libs like Step which I'm still trying to grok cause my js/node-fu is not up to snuff.

Other than that, nodejs makes it ridiculously easy to start hacking away at all kinds of interesting stuff. anything that has to do with sockets or at a higher level, http interaction. Take a look at a post from yesterday to see just how easy, http://news.ycombinator.com/item?id=1301272.


"Apparently there is no built in method to wait on results. There were promisses but they were removed."

Because if you do that, the whole value proposition of Node.js completely falls apart. Now you've blocked the entire system waiting for your result. You might as well be programming in any other blocking language (all of which have Node.js-like libraries, by the way). This is what you get when you try to build concurrency on top of a language fundamentally built on non-concurrent primitives.

Consider going pure Erlang, which does work exactly the way you are looking for it to work. You call a function, which passes around messages and gets the result for you, and the result comes back along the function call, and all the not-blocking is handled by the Erlang VM, totally transparently. (Oh, and you get OTP, which if your server is non-trivial you really need, even if you don't know it yet. And transparent multi-proc support, easy clustering support, couple of other things that Node.js may someday have with great, great, great, great effort and even then they'll still be hacks unless they fundamentally change Javascript to basically become Erlang.)

Node.js is probably going to end up being a huge argument in favor of Erlang, because I suspect you will not be the last to encounter this problem in Node.js. It is absolutely inevitable that any significant application trying to be built in Node.js must collapse into a mess of callbacks and closures that will be very difficult to trace through. That's how it's designed. Any attempt to hack around this will have its own issues with gross hacks or difficulties with branching.

I really don't see Node.js being a success in the long term. It is built on a foundation that is not up to the task. Building a really big Node.js app would be a nightmare, and the reasons why are not going to come out of the foundation easily, if at all.

Here, let me give you an example with my work system I'm building. I have a single function which fans out an RPC request to multiple systems, collates the results with a timeout, and returns the results to the caller (or optionally calls some other code at the end, in the handler process). The initiator does not set up a callback, it just makes a call. The fanout mechanism does not set up a weird time-sliced mechanism to send out the calls, it just does it. There's some callbacks for handling whether it gets an error or a result coming back, which is pretty normal, and note, I don't have to contort around whether those callbacks may themselves want to do something over the network, they're just simple, one-layer callbacks that I would have implemented as callbacks in any language. (Imagine how you'd do that in an event-based system, deal with a response callback that may itself want to do a callback chain. It's perfectly feasible, I can easily see how to do it, but I sure as hell don't want to actually try to code it.) In Erlang, this is very natural; a function call that behind the scenes spawns a process that does what it says and says what it does, and works quite well. In an event-based system, this simple bit of functionality would be a callback explosion. I count a dozen, easily, and it would probably double if I really tried to do it. And that's not my whole system, either, it's just one bit. The multiplicative complexity explosion that occurs with Node.js's approach just isn't feasible.

(Note Erlang handles "events" quite well, indeed, it's a native paradigm for many parts of the system; what it doesn't have is the multiplicative explosion of manually-created event handlers caused by offloading the scheduling onto the programmer.)


re: promises/chaining

Check out:

http://github.com/rsms/node-promise

http://github.com/creationix/step

http://github.com/creationix/do

Did the value proposition of node fall apart?

.

re: multi-proc support

From www.nodejs.org architecture design statement:

"But what about multiple-processor concurrency? Threads are necessary to scale programs to multi-core computers. Processes are necessary to scale to multi-core computers, not memory-sharing threads. The fundamentals of scalable systems are fast networking and non-blocking design—the rest is message passing. In future versions, Node will be able to fork new processes (using the Web Workers API ), but this is something that fits well into the current design."


"re: promises/chaining"

Yup, exactly what I was expecting to see. Not even close to matching Erlang. You're still chopping up your code pretty grotesquely, and you're going to rapidly find out that while that made a few things you were used to doing work well, when you want to take the next step of logical flow that stuff is going to stick in your craw. It's a fairly normal abstraction, in that for the price of making one thing easy it's going to make other things harder.

I implemented that for myself in browser-side javascript years ago, so I actually do know what I'm talking about. (All 3 are really the same basic approach, and it's the only basic approach there is.) It's a little more convenient than the alternative, but it only lightly brushes over a couple of the pointy bits of this approach, and leaves quite a lot of the rest of them still in your face.

" Threads are necessary to scale programs to multi-core computers. Processes are necessary to scale to multi-core computers, not memory-sharing threads. The fundamentals of scalable systems are fast networking and non-blocking design—the rest is message passing. In future versions, Node will be able to fork new processes (using the Web Workers API ), but this is something that fits well into the current design."

I don't have to do anything in Erlang to get multi-processor support. I just run the VM. Rationalizations about why multi-process is hard and it's OK that we don't have it, we don't really need it are irrelevant, I have it in hand. And if you're not familiar with Erlang, you may need to know what it's definition of "process" is: An "Erlang process" is basically a thread, but has process-like isolation from other threads, which is where the word "process" comes in. Erlang essentially automatically runs things in the most-optimized thread-pooling system you've ever seen, and I don't have to think about it. Are you going to be able to spawn off a few ten thousand Web Workers without worrying about the resource usage? (Or hundred thousands? ... or millions?) I'd be surprised. It might be possible, but I'd be surprised.

Bear in mind I'm coming at this as a near-decade user of Javascript and a multi-year professional user of Erlang. I am not unfamiliar with the languages. You can not match Erlang in Javascript, not even with web workers. You can smooth things around, but all you'll get is a yet-more beguiling slide into complexity if you try to do anything at a large scale. (You'd honestly be better off if you hit the limits of Node.js sooner, rather than later.)


Part of my point in the article is that, while node.js is not as good as Erlang, it may be "good enough" for a great many web/network things where Erlang might be considered for its strengths. It's sort of a 'disruptive innovation' situation.


And that's fine. I rather expect you're totally correct in terms of describing what's going to actually happen; Erlang is a non-Algol language and while that's slowly becoming more respectable we've got a long ways to go before it is considered as anything but a negative by the vast bulk of programmers.

It's just that I've actually been down this path a few times with other apps and I feel a responsibility to raise a flag and point out that all applications tend to grow and building with a base that will cause your code to explode in complexity as you tend to grow is not the best plan, but I also know that this is very firmly in the class of things people have to learn for themselves. And the cute little proxies and such aren't bad, it's surprisingly hard to guarantee your app stays in the class of "cute little".

One of my other work apps is actually something built on the Perl wrapper around glib, using its event library, because I ended up having no choice for other reasons (was wrapping a C library and local political concerns wrote Erlang out). And ye gods, the mess, the mess, and the bugs, the bugs. Event chains four or five layers deep in callbacks (multistage login processes being wrapped by other multistage login processes, oi). It's the same exact organizational pattern as Node.js, and it just doesn't scale, even when you know what you're doing. Every trick I know brought to bear to simplify and improve (plugins, simulated generators with goto at a couple points, equivalents to the func chaining hack linked above), but you just can't overcome the weakness of the primitives.


I read your comments on node.js with interest, but I object to being called an 'algol-like' programmer just because I can't deal with erlang.

I work with haskell and lisp just fine, and I can find my way around monads, closures and continuations. It's just the prolog syntax I can't get past.

That and a million little niggles. How do you quit from erl, anyway? Is there a faster way than C-g C-c a? [update: argh, C-\ has thwarted me for years. http://www.erlang.org/faq/getting_started.html It's hard to describe why - it's always obvious in hindsight - but erlang has been extremely painful to learn. I have no trouble with documentation and man pages, but with erlang it seems there's always one more place to check.]

I can't wait for lfe to mature.


Sorry, I only saw this much later. When I say that Erlang is non-Algol, it is not a criticism of a given programmer. It is a criticism of the industry as a whole, that nothing that looks like Algol can succeed anytime soon.

Erlang is full of frustrating quirks and in other contexts you can find me complaining about them and how they don't all go away when you get used to them. (; , . is just plain BS.)


"This can get sloppy."

Indeed it can. I am a fan of flow-js however. It has really helped me to avoid getting sloppy in Node.js.

http://github.com/willconant/flow-js


While concurrency is a strong feature of Erlang, Erlang's _killer_ feature is fault tolerance. For any language to be able to be sufficiently compared to Erlang, it must provide fault tolerance support (either through the language or through a standard library).

I know node.js isn't "gunning" for Erlang but for any language out there: Spend some quality time integrating fault tolerance deep within the language and you'll give Erlang a run for its money. Other than this, there isn't too much that makes Erlang special (sure fast message passing, fast process creation, etc. but the fault tolerance is whats really special)


The scheduler and awareness of its importance is not something you can slap on to any old language and its runtime, IMO. I mean, you could build one into another language, but the mentality of keeping the core system non-blocking is very central to Erlang.


would be nice if the any language that tries to imitate erlang does whatever is mentioned here: http://ulf.wiger.net/weblog/2008/02/06/what-is-erlang-style-... nicely...


Trying to compare a mature, designed from scratch, battle-tested enterprise solution that powers Eriksson's switches with v8 (which is so good to be true) + libevent?

Something wrong with HN.


They get used for some of the same things, so it makes sense to compare them, just as we might compare Java (which also comes from a big company) web stuff with Ruby on Rails. Why don't you point out actual problems in the comparison rather than whine?

Also, calling Erlang "designed from scratch" is a bit odd given that it actually evolved out of some Prolog system they'd built, something that is quite visible in the syntax.


By "designed from scratch", he/she probably means that Erlang's asynchrony is thoroughly integrated, while node.js tries to retrofit such a model onto JS, and still has operations that will cause the whole system to block.

It stopped mattering that Erlang evolved from a Prolog prototype when it ceased running on top of SICStus's IO primitives. (FWIW, Prolog is a really cool language, particularly for prototyping. Event-driven, IO-heavy stuff is just not its strong point. The pattern matching stuff in Erlang comes straight from Prolog, though.)


I think the article is trying to point out that for simpler problems you no longer have to immediately reach for something as robust as Erlang, Node.js might do.

In my mind this is a good thing because more people will realize some problems are too painful to solve in Node.js and they will take a hard look at Erlang. Or they'll get sick of the convoluted syntax hoop-jumping and they'll take a hard look at a Lisp.

I find JavaScript beautiful in a sense because in a very roundabout way it's pulling people towards more advanced PLs.

Pushing a simple solution to its limits is how people evolve to the next thing.


I think it's sad that people are so afraid of trying new languages and investing a bit of their time diversifying that Node.js looks like a viable alternative to Erlang, ever.

It's the ultimate example of the “When you have a hammer, everything looks like a nail” phenomenon.


From where I'm sitting, node.js looks like a great solution for fast, simple, and small web systems, whereas the comparable Erlang systems are more of a pain in the ass to get set up and use. So it is certainly a viable alternative.

Is it the best alternative?

Erlang, as the article states, has some good things going for it; it's better than anything else that I know of for several categories of tasks. The problem is that other things are catching up, and while they may not be "as good", people can and will pick them if they are "good enough" and have other qualities that make them a good choice, such as being easier to learn.

Your comment to me comes across along the same lines of the people thinking digital photography would never surpass the quality of regular film. Maybe node.js won't be the one to catch up and pass Erlang, but my gut feeling is that something will. Scala, maybe?


> Your comment to me comes across along the same lines of the people thinking digital photography would never surpass the quality of regular film. Maybe node.js won't be the one to catch up and pass Erlang, but my gut feeling is that something will. Scala, maybe?

At least Scala is in a similar category. Node.js is basically a bolt-on solution. It doesn't even actually have a comparable threading model, it just has a comfortably familiar one.


I think it's dangerous to ignore "toys", as time and time again they've proven quite capable of taking on superior solutions, and winning, because of other advantages.


No one says to ignore Node.js. It's just a terrible comparison and intellectually lazy javascript programmers seem to be taking advantage of it to remain intellectually lazy.


I have to agree, speaking as a programmer just starting to get comfortable in Javascript with little to no experience in more established functional programming languages. The initial wow factor of having javascript on the server and client side quickly gave way to all the reasons to use alternative approaches.

This project will be the first time many Javascript programmers will brush up against topics of scale such as these, and speaking as one, I'm definitely going to focus on Erlang to explore these problems. (but still play around with Node.js on the side ;)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: