Hacker News new | past | comments | ask | show | jobs | submit login

> The lack of a strong set of standard control and data structures [in JavaScript] means that you end up typing many of the same patterns repeatedly

Care to elaborate? I'm not saying I don't have my own notions of what's missing in JS, but I'd like to hear your take, given your experience.




While not addressed to me, i'd like to chime in with some comments of my own here.

One of my personal gripes with javascript as an environment is that out of the box there is exactly two composite data structures, and both are associative: Objects, and Arrays.

As you are probably aware, Objects are the bread and butter of Javascript and double as full OO objects and also as map/dictionary types with the limitation of only allowing String keys. Arrays have their own quirks but lets leave that aside for now.

Javascript lacks a well understood model of value identity[1]. Without a common model for value identity (i.e. more than reference identity) it becomes very difficult to implement custom data structures (e.g. a BTree for implement a true dictionary type) in a way that can easily (and naturally) be consumed by third parties. Lacking the ability to hook into the [] operator increases the awkwardness for anyone attempting to provide their own custom collections. I would suggest that the lack of good quality collections deployed widely in the javascript world underscores this problem. Contrast this with just about any other language you can think of and it is even more stark.

As an example, any good language probably has a Set datastructure these days. There are two ways to fake it: Degenerate map with the key being the real value and either some sentinal (such as true) or the key itself as the value, or (as is very common in javascript) an array and then doing indexOf.

Let that sink in: a common approach to sets in javascript (when you cant easily provide a string key for your object) is to do a linear search. Yuck.

For a wonderful counter point, have a look at how ClojureScript implements its own collection types, complete with value identity, indentity partitions and proper maps with object keys.

[1] Leaving aside all the unknowns most javascript programmers have about the `valueOf` method.


Welcome to javascript, where everything is a hash table.

Arrays? Secretly hash tables.

Objects? Well, yeah, them too.


Particularly I'm thinking of the inescapable async-all-the-way down, which necessitates endless lambdas. In other languages it's possible to pick a point at which to invert control back to blocking-style; JS's single-thread model makes that impossible. So for instance all calls to the server API have to be callback style; if you have to make serial calls, you can't avoid nested callbacks.

I miss a set type, I miss solid iteration (although coffescript mitigates that), and immutable datatypes would be nice (I've got used to them in Clojure.) I miss a solid FP stdlib, although jQuery has map and filter, which goes a long way.

That's the ones I can immediately think of :).


> So for instance all calls to the server API have to be callback style; if you have to make serial calls, you can't avoid nested callbacks.

I hear this over and over again but I frankly do not get it. I write JavaScript every day and got over the nested callback problem ages ago. I don't say this to refute the point; I legitimately don't get it and feel like maybe I'm doing something wrong because I don't encounter the problem. Here's how I write stuff that requires several callbacks:

  function TakesAWhile() {
 
  }
 
  TakesAWhile.prototype = {
 	start: function() {
 		var xhr = new XMLHttpRequest();
 		xhr.open('POST', 'api/foo', true);
 		xhr.onreadystatechange = this.posted.bind(this);
 		xhr.send('bar');
 	},
 	
 	posted: function(e) {
 		if(!(e.target.readyState !== 4)) {
 			this.complete('error :-(');
 			return;
 		}
 		
 		db.saveSomething(someObject, this.saved.bind(this));
 	},
 	
 	saved: function(e) {
 		db.getFreshCopy('foo', this.got.bind(this));
 	},
	
 	got: function(e) {
 		var foo = e.target.result;
 		this.complete(foo);
 	}
 };
Then I consume it like this:

  var stuff = new TakesAWhile();
  stuff.complete = function(foo) {
  	console.log('All complete!');
  };
  stuff.start();


> inescapable async-all-the-way down, which necessitates endless lambdas. In other languages it's possible to pick a point at which to invert control back to blocking-style

I hear you. Have you heard of iced coffee script ?(http://maxtaco.github.com/coffee-script/) I didn't sleep well the night after I read that.


Looks much like http://tamejs.org/ in the semantics. I guess if you're pre-processing anyway, you may as well pre-process all the way.


Oh, same guy. That'd be why.


I was bummed `await` and `defer` was not merged in. However, after thinking about it, the same result can be had using a good async library. The code is self-documenting if you choose good property names.

.

follow = (from, to, cb) ->

  # Invokes four async operations in a series, which requires 4 `await`, `defer` 
  # using iced. Note how error handling is handled 
  # in one place rather than each step.
  # That's a big drawback for me with await/defer.

  async.series
    user: (cb) -> User.find name:from, cb

    addFollowing: (cb, results) ->
      results.user.following.push to
      User.save results.user, cb

    followee: (cb) ->
      User.find name:to, cb

    addFollower: (cb, results) ->
      results.followee.followers.push from
      User.update results.followee, cb
    
  , (err, results)
    cb err, results


After finally getting over my fear of client-side programming, I finally built a project in JS last week.

I feel exactly the same as you: Javascript, as a language, just does nothing to help you. You've done a better elucidation of it than I could, I just always felt JS was being unhelpful; be it getting the value of an object, be it the inheritance syntax (I have no issues with the prototypal aspect, just the way you express it), lack of good ways to move through a list, the somewhat difficult to understand scoping of 'this'...

It's not that any one thing is especially broken, it's just that all added up I feel like it's not finished, and I'm not Getting Stuff Done as I do with Python.

Google Closure seems to go some of the way there, but I get the feeling that's probably just adding some syntactic sugar to make swallowing the bitterness a bit easier.


This is why I've been dismayed to see JS taking off on the server side. Maybe there's some clever engineering behind Node and maybe taking a free ride on V8 is a lot less work than building a similarly robust VM for Ruby or Python but it just seems wrong to build the next generation of apps on such a flawed language.

The explosion of the web opened the doors to new languages after a long stagnation of client-side code. Why let an accident of browser development history dictate the tools we use for the next 5-10 years?


Node probably will end up like both the JVM and client-side JS have become - a compile targets for better languages. Not ideal, but good enough I expect.


FWIW, JavaScript is getting a Set type (and a Map as well). You can try them in Firefox Nightly.

JavaScript is also getting the ability to change property lookup behavior on objects using Proxy (available since Firefox 4).

Browsers are moving faster, which helps here... and for people using Node, you can use these features as soon as Node gets them.


You should checkout underscore.js for a functional lib. Made by the same guy who did coffeescript and backbobe.js.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

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

Search: