
Writing Eloquent JavaScript Without CoffeeScript - fogus
http://oscargodson.com/#!/article/55075016
======
jashkenas
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.

~~~
fogus
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?"

~~~
bbarthel
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".

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

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

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

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

~~~
Rodrigo_Thauby
My thoughts exactly

------
mquander
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!')
      );

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

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

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

~~~
jashkenas
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

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

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

------
pyeek
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)

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

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

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

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

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

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

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

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

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

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

~~~
subspacedout
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?

------
RyanMcGreal
"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')

------
jakejake
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?

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

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

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

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

------
leetreveil
most of that made me feel sick

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

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

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

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

------
scotty79
This page shows no content on kindle webbrowser.

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

~~~
davej
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?

