Hacker News new | past | comments | ask | show | jobs | submit login
Writing Eloquent JavaScript Without CoffeeScript (oscargodson.com)
57 points by fogus on Dec 9, 2011 | hide | past | favorite | 53 comments



Just to clear one thing up -- Oscar writes:

    > The examples on the CoffeeScript site are purposely written 
    > to be ugly to make CoffeeScript look even prettier.
... not at all. The side-by-side examples on CoffeeScript.org are showing you the compiled output. The point is to demonstrate -- although it's certainly far from perfect -- how CoffeeScript features can be compiled into clean JavaScript. Really, our goal is to make the JS look as nice as possible.


This kind of clarification is exactly why I posted this link. It's great to clear the air in one respect and at the same time ask the question, "is there something on the CS site needing change to avoid this confusion?"


My problem is that I want a comparison of syntax so I can see exactly how Coffeescript is an improvement over the equivalent Javascript.

When I visit the site and I see a table with CoffeeScript on one side and Javascript on the other, my brain sees just enough to verify that the expected elements are all there before it says, "Yep - there is the comparison you wanted".

So while it does clearly state that the JavaScript is the output of the tool, my brain has already decided that it is exactly what I was expecting, and it takes me a second to re-adjust my thoughts.

Ironically, if the output looked less "normal" I probably wouldn't have the same problem, but it is formatted nicely and is good enough that subconsciously my brain tells me "equivalent syntax" and not "compiler output".


My problem is that I don't find the javascript on the main comparison page to be all that bad.

It doesn't do enough to warrant learning the abstraction syntax.


I don't know how Jeremy could make it any clearer. It says:

CoffeeScript on the left, compiled JavaScript output on the right.

Maybe the two halves should have the headers directly aligned above them:

> CoffeeScript

> The JavaScript that it compiles to.

Other than that, it's hard to make it any clearer for its intended audience (people who know JS and know what the words "compiled" and "output" mean).

Still, I'm tempted to upvote the OP as good Friday satire.


Well, it's written in small italic gray at the top of the page. To make it clearer, it could be written "Compiled javascript" on the top right of each compiled javascript code. Or, maybe instead of a left and right rectangle, there could be a kind of arrow to inform that the left side gets automatically changed into the right side instead of showing an equivalence between the two.


This has come up A LOT more than it should. There's a line immediately before the first example explaining exactly what you're looking at. It's slightly absurd to assume that's how you'd actually write those examples in javascript. The compiled javascript is rather approachable, though.


I don't want to sound like an asshole and I'm saying nothing about the author, but in my personal experience I found lining up variables or =s was something I worried about when I first started programming.

Now my mind's eye just totally skips variable declaration when visually code parsing, variable declaration is meaningless drivel that exists only to stop typos (a good purpose).

I had an opinion on the layout of them back then because I wasn't a good enough programmer yet to have an opinion on anything else, I had opinions on things that didn't matter because those were the only things I actually understood well.

Also, again in my personal experience, it's much better to declare them just before you use them for future maintenance, having 4 or 5 declarations at the same time is something I do so rarely now. If you start faffing around laying them out, you're going to be tempted to put them all together.


You should remember that you are not the only person that is going to be trying to read that code (unless it is a personal project, of course). Good layout helps other people read, understand and debug your code at a later date (as well as you at a later date, when you've long since moved on to other pojects in terms of active development work).

Also with Javascript's function-scoped variables and the fact it will let you declare them more than once in a given scope (the second and subsequent decleration being taken as either a NOOP or a basic assignemtn (if there is assignment with the decleration), declaring variables at the point of first use can be dangerous as it is easy, especially if you are messing around in global scope (which is to be availaded generally, but can't always be), to create hard to diagnose bugs due to variable values being clobbered because the same name is used elsewhere.


Same here - I used to line up variables with tabs and such to try to make things look neat and put in lots of dashed lines to separate groups of functionality. I don't know if it's experience or just preference but I don't like doing that anymore.

I find it much more important to put in javadoc style comments to make the code understandable for other users rather than lining things up nicely.

If you're using an IDE you can view all of the variables and methods sorted however you like anyway with a class or outline view.


As someone who writes JS every day, ignoring the fact that I think most of these paradigms are terribly ugly (though the comma placement is acceptable for cleaner diffs), I expected this post to be about actually getting things done eloquently without CoffeeScript. What I got was a blog post about how ternary operators can be written on multiple lines.


My thoughts exactly


Oscar, when your code itself is making little frowny faces at you after you write it, something has gone wrong.

  x == 1
  ? alert(x) 
  :(
     alert('Error'), 
     x = 1, 
     alert('All Fixed!')
  );


Does javascript guarantee a particular order of expression evaluation when there aren't any sequence points?

Alerting 'All Fixed' and afterwards 'Error' seems like it'd be just as valid an interpretation of the code.

Edited to add: Actually, I think the comma operator does do that, so no bad. Though the code is still unsightly...


Python makes little frowns at the end of conditionals and loops that call functions or have sets of boolean logic ):


lol, after reading the article I came back in here to call out that exact same chunk of code and the exact same sad face. I will agree, however for small things the ternary operator is prettier than the if...then...else... syntax

thing[conditional ? 'show' : 'hide']();

instead of:

thing[if conditional then 'show' else 'hide']()


The bit on the comma operator may be used in many other places, and I've seen it result in quite elegant code, particularly in small function bodies. Its use in the ternary here may be questionable, but in any case a good JS dev should know when it is appropriate.

My only gripe is with placement of commas in object literals and variable declarations which has become so common over the past three or four years.

  var x = 1
  ,   y = 2;
or

  var x = 1
     ,y = 2
or

  {
       k: 1
      ,k2: 2
  }
Are terribly unsightly, and do not in any way benefit the maintainer. It's just now you have to worry about the first line rather than the last one.


It should be pointed out that "var a = a || someDefault;" can bite you when 0, "", or null are valid values for a. The empty string in particular can be surprising here at times.


Totally -- I think that 0 (which is a perfectly valid value for a number to be) bites people doing lazy initialization all the time.

For this reason, CoffeeScript provides the existential operator, which asks: does this variable exist? (Is it not null or undefined?) You can use it in the same places you would use "||", as well as some others:

    # In place of `||`
    result = answer ? default

    # Does `object.value` exist?
    if object.value?

    # Lazy initialize the speed of the car:
    car.speed ?= 60

    # Give me the value of `length`, only if `object` exists.
    length = jsonResponse.list.object?.length


I still haven't gone over to CoffeeScript. But I must admit Those are some compelling examples. ?= is especially nice (I miss ||= from Ruby)


In these cases, I would check for the type, so instead of your example, I would say "var a = typeof a !== 'undefined' ? a || someDefault". (Not that that is particularly pretty, it's actually quite ugly.)


That's also a syntax error; I think CoffeeScript wins this round.


When 'false' is a valid value for a you'll also be bitten in the same way.


JavaScript can be pretty too and the examples on the CoffeeScript site are purposely written to be ugly to make CoffeeScript look even prettier.

I'm not sure how many times this will have to be clarified, but the JS code on the CoffeeScript site are not examples, but the compiled JS. Even so, it's in many cases prettier than Oscar Godson's "eloquent" JS, IMHO.


I really don't understand the point of the blog post.

So Javascript can be formatted to look kind of like CoffeeScript?

While I agree that Javascript is often misunderstood, to me his formatting of Javascript is making things much worse, in terms of maintenance (yeah...let's all line up equal signs...).

I personally DO NOT write CoffeeScript but I think the difference between CoffeeScript and Javascript goes beyond formatting. Writing CoffeeScript seems to me to be a syntactic improvement and eliminates some of the need to really learn Javascript (which I think takes quite a bit of effort)


He's got to be trolling. Multiline ternary operators aren't in my book better than an if block.

He also completely misses the point about javascript's global-by-default variables and how easy it is to introduce them with typos, properly building classes, etc.


> He also completely misses the point about javascript's global-by-default variables and how easy it is to introduce them with typos

Using strict mode will avoid these kinds of mistakes.


This is satire, right? ... right? Please?


I guess from MPOV, "eloquent" formatting shouldn't change based on the size of the content... ie the difference between standard indenting and tab-aligning commas vertically. There's nothing eloquent about stepping through a dozen lines of code, tabbing each out, because a value was added that's a little longer than the rest..


He makes a great point in favor of CoffeeScript: making your JavaScript look nice takes much more work without CS. The fact that he is lining up the multi-line string line breaks says loads about how CS will more easily make your JavaScript look good. How many times have you tried to line up your equals signs or colons only to then later add a longer key or var name that required you to further tab over your = or : to keep things lined up.

But feel free to correct me if I'm wrong, but I doubt vanity is the primary reason people are using CS. My number one favorite feature is the list comprehension, and if it didn't have that, I might not be bothering with it.


Using the ternary operator is more "eloquent" than conditionals? That's true iff "eloquent" means terse in terms of number of characters, but I find if(...){} much more readable.


For the sake of a productive discussion, two of the things mentioned about converting ifs to ternaries _could_ be used to create better code.

The ternery operator has some readability problems, but it is an expression, not a statement. Turning statements into expressions is powerful, which is why CoffeeScript's if/then compiles into an expression. Too bad this wan't mentioned.

Likewise, the comma operator allows JavaScript programmers to use a block of consecutive statements as an expression, something the author points out when explaining how to use ternaries in place of if statements.

The notion that you can use a sequence of statements as an expression without having to resort to a "let" form (function () { ...; ...; ...; return foo; })() is another underused construct that can make for improved JavaScript.

Put the two ideas together, and yes you can express a multi-line if statement with shorter keywords, but more importantly you have an if expression without having to wrap it in a function and encumber it with return statements.

I'm sorry that idea wasn't given more attention. If you aren't using JavaScript directly, this pattern may be useful in a more functional, expression-oriented style of programming.


"I find if(...){} much more readable."

Not only is it more readable, it's more correct in the example given.

"if" is a statement. The ternary operator (?:) is an expression, that returns a value. The semantics are different, and using the ternary operator "merely" to replace an if statement, especially where no assignment of the ternary operator's return value is made, is a code smell.

The ternary operator is great if you're replacing a simple "if something assignment to X else other assignment to X." Any other use is questionable.


There are some real problems with these "eloquent" styles.

They work only in a monospaced font. I code in a proportional font, and none of the column alignment tricks will look right when I view the code.

Even if you like to code in a monospaced font, there's no reason to write code that becomes hard to read in a proportional font. It's very easy to write code that is perfectly readable in both monospaced and proportional fonts: you merely forgo these column alignment tricks.

Also, this style of code is a pain to maintain. If you add a variable with a longer name, you have to go up and down adding spaces in front of all the other = signs.

And I find it hard to read even in a monospaced font, e.g.

    var i                       = 123
    ,   j                       = 456
    ,   k                       = 789
    ,   aMuchLongerVariableName = 'foo';
Matching up the initializer values for i, j, and k means my eye has to scan way across a sea of whitespace and hopefully remember which line is which when I get there.

Finally, the example with the escaped newlines all in a vertical column does not do at all what he expects! All those extra spaces become part of the string.


> I code in a proportional font, and none of the column alignment tricks will look right when I view the code.

That's really your problem. If you think people will stop aligning things in their code because you are in the tiny minority that use proportional fonts, you're crazy.

> Matching up the initializer values for i, j, and k means my eye has to scan way across a sea of whitespace and hopefully remember which line is which when I get there.

Nobody's actually going to do what you just showed in real code. Instead, it would look like this:

  var i = 123,
      j = 456,
      k = 789,
      aMuchLongerVariableName = 'foo';
And still look quite good.

> Finally, the example with the escaped newlines all in a vertical column does not do at all what he expects! All those extra spaces become part of the string.

Absolutely, but if you are putting HTML in that string (a while other discussion there) 99% of the time the whitespace will not matter. And for all the other cases, this is no different from multiline string behavior in Python and other languages.


So it's not just me, then. IMO, writing `someThing ||= {}` is much more eloquent than `var someThing = someThing || {}`.

The first point he raises is a valid argument; CoffeeScript's intro does uglify the JS a little to make its point. But it doesn't take much.

> ...merely inaccurate due to a lack of knowledge on JavaScript...

Kinda think the opposite idea was how CoffeeScript came into being, amirite? It was written to make JavaScript look AND act better. It wasn't developed by people that had no idea how to use JavaScript, and it certainly isn't used exclusively by people who don't know how to use JavaScript, too.


I must agree whole heartedly. I feel the author looks at the first few examples on the coffeescript page. Can I see an eloquent example of list comprehension or nested functions?


"CoffeeScript has been getting a lot of press and that's not a bad thing, but it's giving JavaScript a bad wrap.".replace(' wrap', ' rap')


I have to admit that I'm resisting CoffeeScript. It looks interesting but for me it seems like just an extra step for something that isn't bothering me. I'd rather write code that's a little more verbose than to have to "remote control" it via another syntax. Am I missing the boat?


Not really. It's not usually mentioned but CoffeeScript loses a lot of its supposed elegance when you try to do things like chaining. Especially chaining a function that takes a function as an argument. To achieve better looking chaining you'll talk yourself into not using anonymous functions. tldr: whitespace significant languages do not do chaining very elegantly.

Other than that CoffeeScript is pretty cool.


... not so much. A big part of the point of having a minimal function literal, `->` instead of `function(){}`, is that using anonymous functions is a bit more pleasant in any context -- including chaining.

    list.map((num) ->
      num * 2
    ).map((doubled) ->
      doubled + 5
    )
... instead of:

    list.map(function(num) {
      return num * 2;
    }).map(function(doubled) {
      return doubled + 5;
    });
It's not a huge difference. But, by the same token, it's certainly not a reason to avoid the use of anonymous functions.


CoffeeScript is always going to be less verbose than JavaScript, but in the context of a full code file having some functions with parentheses and some without isn't a pleasant consistent experience in my book.

Another thing CoffeeScript handles unelegantly is two anonymous functions (very common when a function needs an onsuccess and an onerror):

  api.get(
    ->
      # Success here.
    ->
      # Failure here.
  )
The benefit of curlies is you get a consistent experience and don't have to go to Stackoverflow to find out when you need commas or parentheses and when you don't.


Putting alerts in what should be a vaguely mathematical/functional construct seems very, very wrong.


most of that made me feel sick


Yeah, it was sort of short and newbie-friendly, but it probably helped some people. I wish that it would have gone into more detail to explain how each of those tricks works so readers could learn why those operators work the way they do. For example, he called using a logical "OR" a "var = var || value way of setting variables."

He should have gone into more detail to explain how ||'s work, how you can have more than just 1 of them, the order in which they are evaluated if you do have more than 1, etc.


The style decisions used in this article do not adhere that well to Crockford's style guide "JS: The Good Parts" and generally not that JSLint friendly.


I can't stand how people assert CoffeeScript looks good compared to JavaScript, as if it's some universally accepted opinion.


I'm not sure, but somehow he made some of those examples look less eloquent then their "ugly" counterpart.


This page shows no content on kindle webbrowser.


It took my browser 20 seconds to render the text. I've no idea why he would load static content dynamically.


Looks lite it's been pulled in from his Posterous blog. Bizarre way of doing it… why not just link to the posterous blog post?


I had to enable three sites in NoScript just to be able to see the blog post.


It's not much better in any browser.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

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

Search: