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.
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.
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.
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.
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 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.
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.
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:
It's a pretty good illustration of why associative arrays in Javascript are a design failure, by conflating different notions in the same implementations:
- objects are not hashes
- hashes are not arrays
It sounds like somebody reading the classic quote by Saint Exupéry, "A designer knows he has achieved perfection not when there is nothing left to add, but when there is nothing left to take away.", and concluding: "Well, if I mash all the elements to a paste, there won't be anything to take away."
Is there some type of injection vulnerability here?
Is it possible to attack a node.js server that creates objects via some API and give it a name that overwrites an internal javascript property? Your content would be the javascript injected code that might get run when the property is used internally?
That's what the original poster is saying, yes. JS does not support a formal separation between the 'attributes' and 'keys' of a hash, so it's a security risk waiting to happen.
In some cases the JS approach is very nice and useful: in Python you see gobs and gobs of classes used to hold data structures, mostly because people don't seem to like dicts in general. I remember a talk, but not the speaker or title of it, where it was pointed out that your Python class is probably a dict plus a function if it has exactly two methods, one of which is called __init__. Python being what it is, you may also extend Python to do what JS does, but slightly more intelligently:
class obj(dict):
def __init__(self, vals={}):
for key in vals:
self[key] = vals[key]
def __setattr__(self, name, value):
self[name] = value
def __getattribute__(self, name):
try:
return dict.__getattribute__(self, name)
except AttributeError:
if name in self:
return self[name]
else:
raise AttributeError("'obj' has no key '%s'" % name)
This lets you use dotted setters/getters with Python without accidentally having x['keys'] = 1 override the obj.keys() method (which it inherits from dict). It's a serious problem in real Python code I've read and written; you create 'classes' which are only instantiated once (and are therefore semantically dicts). So the JS model really has some advantages for easy, clear namespacing (and packaging and enumeration) of identifiers, but yes, there is a potential security question if you allow people to set or get arbitrary JS attributes.
I've found in JS what annoys me a lot is that I can't do this
var x = 'foo'
{x: 1}
Also, where have you seen that class pattern so much? That seems very odd. I almost always find dicts, sometimes __slots__ classes for CPython performance.
I suppose its possible, but the most likely case is just an unhandled exception. JSON does not support string literal notation for values which means in practice any function you replace won't be callable. I suppose someone more clever than I or more likely better motivated could combine this attack with another to do some harm.
Having said that, use underscore for the safe references.
Aw gee, you want a real hash in JavaScript, how hard can it be? Here's a quick and dirty one I whipped up in five minutes. It worked the first time with only one bug - I forgot to remove the prefix in the forEach method at first.
I'm sure I missed something, but this doesn't seem like rocket science.
Of course, you do lose the syntactic sugar of [] dereferencing so it looks like part of the language, but life is full of tradeoffs! :-)
And I suppose there is still a way to break it, if you extend Object.prototype with something that happens to match Hash.prefix. I guess you could use hasOwnPrototype to prevent this. Ah well, maybe I do have a bug after all, but at least it's a good start.
JavaScript already has a perfectly well functioning associative array that can store whatever keys you like with the only gotcha being that strings containing only numbers act like numbers, when used as keys.
> var hash = [];
undefined
> hash
[]
> hash['length']
0
> // Hey! That should have been undefined, not 0!
> hash['length'] = 'test'
RangeError: Invalid array length
> // And I can't set it either!
Also, the part where you're doing hash[hash] doesn't do at all what you think. When you write this code:
hash[hash] = whatever;
What you're really doing is:
hash[ hash.toString() ] = whatever;
And with hash being an array, hash.toString() is highly browser dependent. In Chrome, if you don't have any numeric array keys, then hash.toString() is "" regardless of your non-numeric keys (at least in the version I'm testing). So you may well be really doing this in Chrome:
hash[""] = whatever; // Oops
If you do want to use a native JavaScript type as a hash, the one to use is Object, not Array. Simply change the first line of your test to:
var hash = {};
and go from there.
This still doesn't solve the name collisions, but is plenty useful anyway.
If you do want a more fool-proof hash that lets you use any string as a key without fear, I'm pretty sure you need to write some code like the Hash class I posted. You still couldn't do the hash[hash] - or hash.get(hash) - because of the dependence on .toString(), but any string key would work. You could even get fancy and give the Hash class some kind of useful .toString() method so you could use hash[hash] - having your own code here opens up those kinds of possibilities.
You're right, I was too quick to reply. I'm not really a javascript programmer, I figured the Array type would have different semantics on the [] operator than a plain Object.
I'm not a JS programmer, but isn't that just an array? Which extends Object. Which has all the failings that the article mentions? What happens when you try to insert hasOwnProperty? Do you lose access to the superclass hasOwnProperty like the {} object literal's drawback the article mentions? I suspect you do.
When I first saw this post, it didn't include the following snippet:
Object.create(null);
I disagreed adamantly that a hash with pre-defined names is not a hash. The language already provides a means to get a hash without the pre-defined names, and any clever person can hack around naming collisions regardless. He now notes these things at the end of the article, but then the entire argument doesn't imply that a hash is not a hash. He does a good job pointing out a mistake ALMOST EVERYONE makes, and I applaud that, but the title is horribly misleading, even when given the proper context.
Also, @mcot2, I didn't intend to post as a reply to you, but since I have, to answer your question, collections (Maps, Sets, and WeakMaps) are available in V8 and consequently Node already (via --harmony flags). Because the implementations of these with get/set is not tied to the object's properties, these don't have the same problem.
I'm sorry about that. I went back later to edit in a comment to make it clear that I had incorporated your point into my response but the edit had expired.
I think this problem can be easily solved by encapsulating access/creation methods of posts objects in a object say postStore where posts variable is private property and the object have savePost(slug) and getPost(slug) methods where access/creation methods are defined by yourself. If posts object is that much mission critical than it should not be exposed to outer world.
Instead of writing code around the problem, its better to just use a safe reference (ie, use Underscore's has method which will call Object.prototype.hasOwnProperty). This way code stays both simple and safe.
Other than lists which can be represented by JSON arrays, hashes do fine jobs at describing most data and most "objects".
This post goes off the rails almost immediately with "Normally this would work fine, but let’s consider that the user could pick any of the keys that are present in any JavaScript object as a name." WTF? The author almost immediately is confusing his/her current situation with the request body and what's in it.
Then we find ourselves quizzically with "We therefore change our code to leverage hasOwnProperty". Umm, I don't think most developers would find themselves "therefore" doing this.
If I understood the article’s example, he’s suggesting the (perfectly plausible) use case of a new blog post named, e.g., `hasOwnProperty`. Then they would want to set a key named `hasOwnProperty` in the `posts` object, but `hasOwnProperty` is already defined (via inheritance, since all objects have it) as a function (well, native code)… so now you have either (a) prevented your blog from allowing a reasonable blog post title, or (b) seriously mucked up your blog by accepting a blog post title that has the side effect of redefining a basic object method.
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.