Hacker News new | ask | show | jobs
by drewying 4226 days ago
Kudos to the creator. Writing something like this takes a lot of effort and it looks like they did a great job! Well done!

With that said, on wider level, what's the allure of these JavaScript replacement languages? Is JavaScript syntax really that difficult for some developers to wrap their head around? I can understand something like Dart that has an underlying goal of performance, but the purposes of things like this or CoffeeScript genuinely confuse me.

4 comments

It's not that JavaScript syntax is difficult. It's that there are some common patterns that repeat themselves so much times.

For example, safe object navigation. This code in Spider/CoffeeScript:

    var x = a?.b?.c?.d;
compiles to something like:

    var x = typeof a !== "undefined" && a && a.b && a.b.c ? a.b.c.d : void 0;
You can also handle problems like this via libraries. For example, underscore-contrib [1] does it this way:

    var x = _.getPath(a, "b.c.d");
There are definitely advantages to having this pattern baked into the language, though.

[1] http://documentcloud.github.io/underscore-contrib/

I've been using node-jsx and jsx-loader to bring JS Harmony syntax into projects I'm working on now. The last great hurdle to make JS a language that's easy to express in is the existential operator. It sucks how often you have to manually null-check in JS.

I'm mighty tempted to write a Webpack plugin to make `?` usable in vanilla JS.

Another reason to prefer CoffeeScript is because of its low cost of both defining and calling functions. The combination makes functional programming, including working with callbacks and promises, much less of a headache.

Even if you don't know CS very well, I dare you to take a look at the JavaScript this compiles to and call it more readable:

    (req, res)->
      getUserIds(req.query)
      .then (ids)->
        Promise.all ids.map (id)-> 
          getUser(id).then (user)-> user.friends.count
      .then (response)-> res.send 200, response
      .catch (error)-> res.send 500, error
I believe your example is a perfect demonstration of how coffeescript can cause unintended bugs.

You code compiles to:

  (function(req, res) {
    return getUserIds(req.query).then(function(ids) {
      return Promise.all(ids.map(function(id) {
        return getUser(id).then(function(user) {
          return user.friends.count;
        });
      }));
    }).then(function(response) {
      return res.send(200, response);
    })["catch"](function(error) {
      return res.send(500, error);
    });
  });
Not what intended, I assume :)
I doubt anyone will see this, but just for posterity: Still not seeing a bug in this code, and under the tentative assumption that none exists, I find it amusing that you were confused by what you think is the more readable version :)
Well, that's definitely the JavaScript I intended to create :) Is there a bug in my logic somewhere?

Edit: But that aside, to be fair, I'll readily agree that it is easy to mess up CoffeeScript's significant whitespace if you don't pay attention to it. For example, you add a multi-line callback to one of those single-line callbacks at your peril!

But the tradeoff is, no mismatched braces/parenteses. Personally, I find the warts are not that hard to avoid, and the overall impact on my productivity is positive.

I guess he's referring to the implicit returns which are a pain in the neck to deal with.
Implicit returns are the norm in ES6's arrow functions. I use CoffeeScript for most of my personal coding, and I can think of exactly one situation where an implicit return got me in trouble. Generally, if you don't care enough about what your function returns to check it, then it's likely the calling function doesn't either, assuming you're familiar with the particular API you're working with.
In LiveScript there's syntax to explicitly omit any return value, it's just a function with !-> instead of -> for the arrow.
That's a question of perspective, I think-- if we're calling this function from somewhere, and we care about what it does, we need those returns.
More concise? Yes.

More readable? Eh...

I can grok either at about the same speed.

That's fair. Personally, I spend a lot of time reading and writing JavaScript, and I still can't not find all the braces distracting.

I mean, if you're talking about a deep understanding of what the code does, I agree with you. But when you're writing a lot of code that basically looks like that, it's useful to be able to take it in at a glance.

The main reasons I reach for Coffeescript for my personal projects are: * built-in support for comprehensions and other array/object operations * simple syntax for context binding * automatic module isolation. These eliminate a lot of boilerplate littering my JS code. At my company gig we use JS but rely heavily on Underscore to address the same pain points; I prefer to have it built into the language syntax instead. ES6 probably has enough of this built in to make me switch back eventually.
It's relatively easy to build a compile-to-js language because of the pre-existing tooling.