Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The fact is, it's 2012. We all appreciate V8 making the web fast. It's stuff like this, however, that makes me question the sanity of those still promoting node.js

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.



The people waiting for the programming community to suddenly wake up and realize how wrong they were about Javascript all these years remind me of all the people still waiting for Castro to die.

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.


Trying to make one's tools better is always worth it. Typescript is to me the most exciting thing to have happened to JS, better than all the so called libraries that have to be declared inside a function (!!) so that the scope doesn't get completely screwed up.

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.


> the so called libraries that have to be declared inside a function (!!)

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...


as a note this works in JS too.

  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)


I think JS is in a unique position because of its availability in the browser. Sadly I can't see any good way to get languages I like into the browser.


>why are such languages more popular than their more ideologically pure cousins?

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.


Or, alternately, we'd all be griping about still having to use Python 1.x until people stopped using IE. It's only been the last year or so that you could start thinking about sufficiently large percentages of your users to be running current browsers.


I'd like to know why erlang doesn't count?

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.


I'd assume erlang doesn't count cause the way you do concurrency in it is the opposite of you do it in node (a bunch of stateless processes communicating over stateful channels vs a single stateful process with callback spaghetti)


There is no channel in Erlang. Each process has a mailbox. Each process is stateful. Node has only 1 and it works with callbacks as a way to do cooperative scheduling, Erlang has N of them and they work through message passing, using preemptive scheduling.

They have nearly nothing in common.


They're more or less duals: move the functions to the data via closure thunks as callbacks, versus move the data to the function via messages.


You put it much better than I could.


They don't have the same concurrency model.

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.


They look different but what matters is the same.

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.


Preemptive scheduling also allows to add some interesting real-time guarantees by knowing some processes will be scheduled when they need to be busy, or to do it based on how much is waiting for them by interrupting others.

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.


JS has all sorts of problems, but I don't think being async by default is one of them. It's different, yes, but being async by default can be really useful for some tasks.


It certainly can be really useful and thinking in terms of continuation passing style can be kinda fun and enlightening, but it's a pretty awful way to write code normally.

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


I've never actually understood why the async thing is so hated. Spend some time in node, and you'll get used to it.

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 issue is definitely not familiarity. I've written more async code in more languages than most (node, java, ruby, clojure).

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.


>Does JS work? Sure, but believing JS is good is a special kind of delusion.

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.


It actually isn't completely alone in using an asynchronous paradigm, as you suggest. Delegates in iOS/Cocoa and events in Java work in a similar fashion. Function-queue architectures are not unique to Javascript.


My point exactly. Both of those languages are synchronous by default, async is an option. JS is async only pretty much*

* while there are blocking calls in node, they are by far the exception. It is not multi-paradigm like Java


I'm not sure I see the distinction you're identifying. If you're ever written code on the iPhone, everything is done via events. All the code you write is responding to an event fired in the runtime. Any synchronous network calls you make will block the UI thread, so asynchronous calls are the right way to access network resources. This same reasoning is why Node.js libraries are primarily async. It's the right thing to do.

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.


Believing anything is good, takes a special kind of delusion. To have and behold one opinion is... well there is history that shows where that goes.

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?


You have overstated how bad JS is in practice. Libraries easily fill in the gaps of the language- Async and Underscore for example. Nodejs is easily the best evented framework for many work cases and that is why it is used.


JS has two kinds of problems: the kinds of problems like a single number class, and the kinds of problems like implicit global scope. The latter are solved by reading JavaScript: The Good Parts and/or writing CoffeeScript. The former is a result of an idiotically simple core of the language, but also because nobody is clamoring for it. As a trade-off, though, you get JSON!


How is JSON a benefit from a single number class? Python has integers and floats, yet JSON syntax is (almost) valid Python code, including the numbers.


> JS Can't even perform integer math

Can you explain the integer math thing? What exactly can't it do?


JavaScript's Number type is double floating point:

    $ 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
    true


I don't see how this is any different from overflowing an int32 in any other programming language. Sure, with an int, x != x + 1 even after an overflow, but your program is still going to crash when it tries to bill you for negative two billion widgets.

If 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.


"Overflowing an int" is something that I worry about when I'm thinking in terms of memory layout of data. I shouldn't have to worry about it when working at a higher level of abstraction. Python handles this correctly:

  >>> int('0x7fffffff', 16)
  2147483647
  >>> int('0x7fffffff', 16) + 1
  2147483648L


The difference is, in other programming languages you usually have a choice to use an integer number type.


Thanks for the example.

I'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)?


people usually run into the issue from time to time when using JSON to transmit numbers to a javascript process, for example[0][1][2]

[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...



Someone should implement Lua in browsers.




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

Search: