
A Case Against Using CoffeeScript - Liu
http://ryanflorence.com/2011/2012/case-against-coffeescript/
======
jashkenas
There has always been a _strong_ "case against using CoffeeScript", from day
one. Like any other new language, it's a new, strange thing to learn, there's
new tools and a new compiler, and your team doesn't already know it.

In addition, CoffeeScript has it's own distinct burden to bear: the entire
point is to compile (in as straightforward a fashion as we can manage) into
JavaScript. That you're debugging JavaScript when you run CoffeeScript in
production should be no surprise -- that's the point. But it's also quite a
large hurdle to jump.

What's interesting about CoffeeScript is that despite there being a strong
case against using it -- and I try to make the same case in my workplace --
people still find it useful enough, and transparent enough, to use it
regardless.

As of this morning, CoffeeScript is the 13th most popular language on GitHub,
and the second most popular module in npm, after Underscore. All of the top
ten languages on GitHub date from the mid-1990s or earlier.

<https://github.com/languages/> <http://search.npmjs.org/>

The better question is not "What is the case against using CoffeeScript?" ...
but instead: How is it that despite all of the obvious hurdles stacked against
a new source-to-source language, people are actually using CoffeeScript?

That's the question I'd like to know the answer to.

~~~
roestava
With JavaScript ordinary developers hit a wall at some point and can't make
further progress. Like Java has shown, how good the language is seems
secondary to how good the implementation, the runtime, is.

JavaScript runtimes have kept on improving and with the V8/Node.JS combination
have started taking over the server-side code.

With careful engineering, developers can get even further with just JavaScript
the language. I wonder for instance whether using the Google Closure Tools can
bring more gains there. Such tools help with checking the code for common
pitfalls and the style guidelines also help a bunch. Plus, they might help
with deployment, with the packaging for the specific program you've written so
you don't need to package up all the library with it. Then you don't need to
feel ashamed of making use of lots of library code, if only the part of it
that you're using gets deployed.

Still, working with JavaScript directly can also bring debugging challenges,
even more when you're trying to debug code that has been mangled since leaving
your library source files.

Languages like CoffeeScript and Dart have success because the alternative in
pure JavaScript is still quite painful, as I've mentioned above. It's a
mistake to dismiss languages like CoffeeScript and Dart because you want that
50% extra performance.

Still, CoffeeScript is a concept. It could be said to have been over-
engineered in places. Some of the stewards of JavaScript would have found it
better if it was more like a JavaScript with JSLint turned on and some
niceties on top of it.

~~~
showell30
Just to clarify one thing, it's very unlikely that you'll take a 50%
performance hit when moving from JS to CoffeeScript. That may be true for Dart
as well--I don't know.

Also, since CoffeeScript transcompiles to JS, it will generally reap the
benefits of future improvements to JS runtimes, packaging tools, etc.

~~~
rbrcurtis
I have high hopes for dart, but so far it produces absolutely crap javascript.
[http://www.reddit.com/r/programming/comments/ml62k/hello_wor...](http://www.reddit.com/r/programming/comments/ml62k/hello_world_in_dart_compiled_to_javascript_redux/)

------
RobertKohr
The debugging complexity is more than just a fair point. It is what kills the
language for me.

I spend way more time debugging code than writing it. I suspect most coders
do. Programming has taught me that I am far from perfect.

Give me a language where I can jump right to the problem and my debugger will
tell me how I goofed up, and I can look at it as a potential language I will
use. Give me something where you double my debug time (which will add probably
30% to my total programming time) and I will ignore it. It doesn't matter how
pretty and short it makes the code. Give me error line numbers or go home.

If you make my debugging more of a chore than it already is, you ain't no
friend of mine.

I also agree with the author on the need for symbols rather than words in
languages. It may make people feel all warm and fuzzy to write what looks like
english, but && trumps and every day. {} or () wrapping something gives me a
lot of info about what is going on and with little mental parsing.

In the end, CS just doesn't deliver a advantage to me that is worth moving
away from something as easy to code in as JS, warts and all. And I have tried
very hard to want to like it.

~~~
illamint
I've been working on a large project in CoffeeScript for about 9 months now
and have never noticed or felt burdened by the translation between JavaScript
source line to CoffeeScript source line in debugging. Maybe it's different for
others, but the code is so structurally similar that there shouldn't be a
major difference. It's not like looking at the assembler output of a C++
program and having to demangle names and deal with compiler-generated labels
and jumps etc.; the structure of the program is still the same, it's just the
syntax that's really only mildly different.

Of course, though, it comes down to personal preference. Don't want to use CS?
Fine! Great! Go hog wild! No one's forcing you to. Me, though? I'll never go
back.

------
antirez
I agree with the author of this post. What is interesting for me is how people
are happy to use an intermediate layer in front of javascript just to gain
some _syntax_ and not real semantics.

CoffeeScript does not really change the complexity of your program. I agree
that in modern languages it is a good idea to avoid all this parens and
useless syntax that we have in Javascript, ObjectiveC, and so forth, and I
hope next versions of Javascript could even change syntax at some point, but
to use an intermediate layer/compiler/translation stuff just for that... is
strange.

~~~
chc
There are real semantic differences in CoffeeScript. As listed by jashkenas
himself more than a year ago in response to the same accusation:

Leaving features off the table and just talking about semantic cleanups,
here's a few:

* Switch statement doesn't fall-through by default.

* Variables don't need to be declared with "var", and can't ever become global accidentally.

* Equality is strict, using `===`, if you want coercive equality, you coerce the object yourself.

* Loops that are used to generate functions close over their index variables, so that all inner functions don't share the final value of the index. This is the same problem that ECMAScript Harmony introduces "let" to solve.

* Splats largely replace use of the "arguments" object, so you don't get bit by "arguments" only being a faux-array.

* Comparisons can be chained, as in Python -- so you can write: "100 > x > 25", and have the answer be correct.

* Multiline strings are valid without having to escape the newline.

* And the big one: everything in CoffeeScript is an expression. Without having to use temporary variables, you can return the result of an if/else from a function, pass a comprehension (loop) directly into a function call, assign the result of a try/catch, and so on.

(<http://news.ycombinator.com/item?id=1697586>)

~~~
antirez
That's definitely more semantics that I thought it contained, thanks for the
clarification. However for the same reasons the debugging problems are
probably more severe than I realized before.

~~~
chc
As I said elsewhere, unless you believe the CoffeeScript compiler is
introducing bugs into correct code, I'm not sure I understand your concern.
Does the fact that C has different semantics from machine code generally make
debugging C harder than debugging machine code? There is still a very close
relationship between the CoffeeScript and the JavaScript — closer than, say,
what you get with GWT or Closure Compiler. The ease of reading and writing and
the reduction in source code length is worth the minor context switch to many
people. It's easier to spot a bug in five concise lines than in 25 lines of
mostly boilerplate.

~~~
antirez
For not using Javascript itself, that is widely understood across the
programming community, that is not perfect but either not a disaster as a
language, I would expect a lot more gains from a to-javascript-compiler. Here
what I see is that there are a few semantical changes and syntax changes, but
for me this is not enough to switch.

What I think the value of CoffeeScript could be is to show how Javascript
could be improved in the next versions.

------
geraldalewis
> Verbally Readable !== Quicker Comprehension

-> is Coffee-Script's greatest trick. When I first started poking through the codebase, it would take me ages to 'sound out' each line. Coffee-Script is succinct not simply because its syntax is short, but because it is dense. Everything is an `expression`, which means I can be more expressive/loc.

I can now read it as fast as any other language, which means I can comprehend
code faster.

> doSomething() if five and six and seven

That was difficult for me to parse as well until I saw it enough. Which is
true of everything new I have ever learned. Some syntax took me out of the C
comfort zone, and I am better for it. There's a _feel_ that code written "out
of order" has that I instinctively like for some scenarios.

> Therefore it will never really be supported natively, and will always be a
> compile-to-JS language, and will therefore always have a terrible debugging
> experience.

Mozilla has been working on this issue in earnest
(<https://github.com/mozilla/source-map>). It seems that compile-to-JS
languages may be part of some greater strategy. Surely, Google must be working
on something similar for Dart. Some progress has been made on the GitHub
Issue: <https://github.com/jashkenas/coffee-script/issues/558>

~~~
ryanflorence
Source mapping will be helpful, but clearly fewer people than I'd expect know
how to use the debugging tools in their browser to the extent that I use them.

I don't want a line number, I want a break point or watch expression _in my
code_ while I'm debugging, I don't want to go back to my editor until I know
the state of my app that's causing problems.

It is all very minor, but it piles up and slows me down.

~~~
javajosh
Perhaps an article (or webcast) on how you use your debugging tools is in
order.

------
Cushman

      > This is really weird:
    
      getUser = (id) ->
        url = "users/#{id}"
        dfd = $.ajax
          url: url
          format: 'json'
          method: 'get'
        url: url
        promise: dfd.promise()
    
      > It’s hard to recognize instantly that I’m actually 
      > calling $.ajax, not just assigning it. If you don’t know 
      > CoffeeScript, I’m sure the last two lines are totally 
      > baffling.
    

Um... I agree, but as someone who _does_ know the language, that's clear,
unambiguous and easy to read. I maybe wouldn't use implicit object return
there, but it doesn't surprise me to see it.

In fact, I'll make a positive argument for the implicit call syntax: the
whitespace under 'dfd' tells me, without reading any further, that the line is
a call which takes an object argument. Without significant whitespace, I
couldn't rule out it being just a typo.

------
sunsoong
These are all valid points. Debugging is probably the most significant. I
agree that the syntax can potentially make CoffeeScript hard to read, but this
can be easily avoided.

One of the nice thing about CoffeeScript is that it allows one to be selective
about the syntax. For example, unlike the author I will use keywords like is,
isnt, or, and, yes, no, on, off because I find it easier to read that way.
However, I dislike the calling functions without the parentheses and I dislike
the long one-line comprehensions. Instead of doing this:

    
    
       eat cheese for cheese in cheeses when cheese is blue
    

I would do:

    
    
       for cheese in cheeses
         if cheese is blue
           eat(cheese)
    

I can have a minimal syntax, but retain some of the unnecessary bits to make
it easier to read. If the author finds themselves writing code that is hard to
read, they should just not write it that way. Write it the way you (and your
team) like it to be written.

------
cheald
The increase in debugging complexity is a fair point, and it does add an extra
step in between finding a problem and fixing it. However, in practice, I'm not
sure I've ever had this be a _major_ problem; I've had more problems related
to bad error messages from the Coffeescript compiler (generally due to
significant-whitespace errors) than I have had in trying to associate
Javascript to its source Coffeescript.

The rest of the examples, though, don't hold much water. The takeaway from
them is "it's possible to write terribly-factored code, even in a pretty
language".

    
    
        doSomething() if five and six and seven
    

Can be rewritten as this, if it's more comfortable for you:

    
    
        if (five && six && seven) then doSomething()
    

!=, &&, ||, (), and the like are still usable in Coffeescript. If it makes the
code easier to read, then use them!

The whole concern with list comprehension syntax order is sort of a red
herring - it works that way in Javascript 1.8, as well! In fact, nearly every
language that implements list comprehension does it similarly. 160-column
1-liners are evil in any language, not just Coffeescript. If you don't like
the "method, loop, condition" syntax of list comprehensions, that's a problem
with list comprehensions, not with Coffeescript.

The points about the implicit returns and parentheses-less calls apply, as
well. When it makes sense to explicitly use them for code clarity, _use them_.

For example, your confusing getUser method can be easily written as:

    
    
        getUser = (id) ->
          url = "users/#{id}"
          dfd = $.ajax(
            url: url
            format: 'json'
            method: 'get'
          )
          return { url: url, promise: dfd.promise() }
    

Voila, it's still coffeescript, and it's very readable, easy to understand,
and not at all difficult to maintain.

The fat arrow, like the rest of the examples, is yet-another-case of "Yes, you
can shoot yourself in the face with it, if you abuse it". Event binding isn't
the only case when you need to preserve scope! Sometimes (frequently, even)
you need to pass around an anonymous function bound to a specific scope. The
fat arrow is explicitly for that sort of work. If you abuse it every time you
could otherwise just call call() or apply() (because you have access to the
scope to invoke the function on, in addition to the function itself), then
yeah, it's bad.

Have you even _looked_ at the implementation of $.proxy() used in your
examples there? Guess what it does? It creates a new anonymous function, binds
it to the passed-in scope, and returns it. Which is _exactly_ what the fat
arrow does in Coffeescript. Why is it evil in Coffeescript, but okay in
jQuery? Because you aren't aware it's happening?

Your "This is how you should do it" method in Coffeescript is wrong. It should
be something like this:

    
    
        widget =
          attach: ->
            @el.bind 'click', @handler
          handler: (event) =>
            doStuffWithThis()
    

That's clearer than any of your examples, Just Works, doesn't have a jQuery
dependency, and is even less code than your corrected example. First-class
functions have the `this` problem in _every_ language, and the fat arrow is
very nice syntactic sugar for what you have to do anyway.

The purpose of Coffeescript is to make your life as a Javascript developer
easier. If you're using it to make your life harder, you're doing it wrong.
It's not a case against using Coffeescript - it's a case against writing
terrible code.

~~~
IsaacSchlueter
I think part of the gist of the article was that abused CoffeeScript is more
bad than abused JavaScript. So, yes, of course, you can do everything
differently. But the point is, in the moment when writing it, it's not
confusing, and doesn't stand out as a bad thing. Later, when you look at it,
it IS confusing.

~~~
cheald
I dunno. I think that a lot of that is just a matter of developer maturity and
code discipline. If you can't recognize a code smell when you're writing code,
the problem is probably that you aren't mature enough as a developer, not that
the language is bad for allowing it. I don't think that most seasoned
developers would look at that 160-column list comprehension, say "okay, that
works!" and move on to the next task. They'd say "okay, that works, but holy
crap it's ugly. Quick, to the refactormobile!" I've seen 160+ column nested
ternary operations in pure Javascript that make the aforementioned
comprehension look positively poetic.

I've seen some genuinely horrible Javascript. Like, stuff that so terribly
abuses the language without any comprehension whatsoever of closures or
context binding and only works because the author got _stupidly lucky_ and/or
abused globals so badly that the code was effectively one giant function. In
both cases, bad developers writing bad code are going to produce
unmaintainable messes. Doesn't mean that the language should be avoided.
Garbage in, garbage out.

~~~
tjholowaychuk
I've seen terrible JS, but I've seen much worse CS. Most programmers have
relatively no sense of organization, and when unleashed with CS create things
far more nasty than their JS counterparts.

nasty: [https://github.com/jashkenas/coffee-
script/blob/master/src/r...](https://github.com/jashkenas/coffee-
script/blob/master/src/rewriter.coffee#L93)

nasty: [https://github.com/jashkenas/coffee-
script/blob/master/src/o...](https://github.com/jashkenas/coffee-
script/blob/master/src/optparse.coffee#L36)

nasty: [https://github.com/jashkenas/coffee-
script/blob/master/src/c...](https://github.com/jashkenas/coffee-
script/blob/master/src/command.coffee#L89)

sexy: [https://github.com/jashkenas/coffee-
script/blob/master/src/g...](https://github.com/jashkenas/coffee-
script/blob/master/src/grammar.coffee#L278)

~~~
thejefflarson
I've seen terrible assembly but I've seen much worse C. Most programmers have
relatively no sense of organization, and when unleashed with C create things
far more nasty than their assembly counterparts.

nasty:
[https://github.com/mirrors/gcc/blob/master/gcc/c-family/c-co...](https://github.com/mirrors/gcc/blob/master/gcc/c-family/c-common.c#L1976)

nasty:
[https://github.com/mirrors/gcc/blob/master/gcc/c-family/c-le...](https://github.com/mirrors/gcc/blob/master/gcc/c-family/c-lex.c#L937)

But you get the idea. I'm merely pointing out that compilers are tricky and
complicated beasts. And especially in the rewriter CS has to jump through
hoops to disambiguate.

~~~
tjholowaychuk
I dont know if I would call CS complicated, but yeah you'll get that all the
way down. Noobs will write their js, bigger noobs write CS, smarter people off
writing C, and even smarter people writing ASM. Most will still write nasty
code regardless but the ambiguity in CS makes this far more painful to consume

------
ms123
Am I the only one to completely disagree with the author?

It's important not to mix everything. CoffeeScript is a _language_. There just
happen to have an _implementation_ for it.

This invalidates the "debug" workflow problem. Let me restate the CS debugging
workflow:

    
    
        Start discovering the problem in the code I wrote.
        Fix it in the CS
        Problem fixed, move on, otherwise start over.
    

A computer language is by definition a mean to express unambiguous statements.
So does CS. So does the other languages. The resulting program will do exactly
what your code asked to.

Do we check compiled code when we code in C? Do we look at the Bytecode when
we write Java?

The fact that CS compiles to JS is an "implementation detail". That's the CS
compiler's job. If you don't trust it, don't use it.

~~~
dextorious
You take the "useless pedantic comment of the year" award.

Yeah, "it's a language". In bloody THEORY.

In reality it's also ONE, and only ONE, specific implementation widely used.
In reality the language IS the compiler.

And that implementation compiles to JS, not as an implementation detail but as
it's sole reason to exist.

~~~
ms123
Thanks for the award.

Yup, there's only one implementation. But doesn't in change? What will the
compiled code be like in 3 years from now?

The compiled code's prupose is to be optimised, not consistent. This is my
point.

By restricting yourself to think Javascript when you're coding in
CoffeeScript, you're producing a code that sucks in JS and in CS.

------
phzbOx
To quote the author:

"Check out this one-liner I pulled out of the first .coffee file I randomly
opened from our application:

scores = (student["assignment_#{@assignment.id}"].score for own idx, student
of @gradebook.students when student["assignment_#{@assignment.id}"]?.score?)

That’s 160 columns of “readable code”..."

You can write a 160 columns of unreadable code in any languages. If you guys
enjoy coding like that, don't blame coffeescript.

You might be right however that it is "more tempting". For instance, with
scheme, it's really easy to start using macro and redefining everything; or to
nest lambdas into lambdas into lambdas "because you can do it and it avoids
using variables".

Still, I think it's the programmer's job to write clear code, whatever the
language.

------
sharjeel
Seems like author is trying to learn a new language and is having a hard time
getting out of the shell he created around him with experience. During the
struggle he wrote this post.

I had exactly same feelings about one-liners and understanding succint
statements when I was learning Python after years of programming in C.

------
jrockway
_My code is more readable for me than yours. That’s just how it is. While the
JavaScript CoffeeScript compiles looks decent, it’s still not mine._

That would change if you practiced reading other peoples' code. When I see my
code, I often think, "yeah, I wrote this" because I know how I name things,
but other than that, my code looks like everyone else's code. I know this
because I based my style on what other people do, rather than just inventing
my own. (At work, people like to write Python likeItsJavaOrSomething, and I
refuse to follow that convention. While ugly, it doesn't make the code
amazingly hard to read. You get used to it with practice.)

Now, compiler output is another thing, but c'mon. Sometimes I have to figure
out what the computer is doing by reading memory dumps in gdb or the assembly
output of gcc -O3. Complaining about the output of a JavaScript compiler is
just silly; do it more and you'll figure it out. Programming is all pattern
recognition, and if you can't understand patterns in the output of your
toolchain, then you aren't using the tools enough.

People also like to complain about things like GHC's type inference errors or
Perl's "confess" dumps. I personally have no problem extracting the
information I need from them. I write a lot of programs and they fail a lot,
so I've gotten good at reading the debug messages. Instead of saying, "this is
too hard", try harder, and soon your life will be much better.

~~~
ryanflorence
> That would change if you practiced reading other peoples' code.

I'm really active on github, and actually read the source code of a lot of
projects instead of reading books, and contribute to a bunch of them too.
Quite assuming of you to assume I don't.

My code, since I wrote it, will always be easier to understand because I dealt
with every problem--not because of the style.

~~~
sirclueless
I totally agree with you there. There is something totally different about
reviewing someone else's code versus reading your own. Because even if you
wrote it a long time ago, it's still easy to reverse-engineer the purpose of
everything you did.

------
ricardobeat
As a year-long CoffeeScript user, I have a few points to rebut:

debugging workflow: he makes a long list of bullet points, when in practice
you can find the error directly in your coffeescript code 90% of the time,
since you have a clear image of what it's compiling to and errors tend to
happen on the piece you're working on. Hopefully source-mapping in
Firebug/Inspector will be ready in a few months and end this discussion.

"We Process Images and Symbols Faster than Words": It has been demonstrated
that the understanding of text is based on the same principle, we don't "read"
words, we identify them. _and_ and _or_ are as much a symbol as _==_ and _& &_
(which you still can use if you think they are more visible).

"ugly syntax": the examples are ugly. Don't use a trailing if for long
conditions, don't create huge one-line comprehensions. You can do worse in
javascript.

    
    
        if five and six and seven
          doSomething()
    

"bad parts": every language has bad parts, but the example is just bad
practice. Just because you can omit _return_ and start an object literal
without indentation doesn't mean you should.

    
    
        getUser = (id) ->
    
          dfd = $.ajax
            url: "users/#{id}"
            format: 'json'
            method: 'get'
    
          return {
            url: url
            promise: dfd.promise()
          }
    

"Significant White-space Means CoffeeScript Will Always Be Compiled": what? No
it doesn't. You can compress coffeescript, you can't _minify_ it.

Readability is not a strength of most javascript code out there.

~~~
ricardobeat
Comments are welcome.

------
chc
The debugging complaint is valid, but a) doesn't generally seem _that_
troublesome in practice (especially given the still-crude state of JavaScript
debugging tools in general), and b) will be a lot less valid in the near
future, as WebKit, Google and Mozilla are all adopting support for alternative
languages in their respective JavaScript implementations IIRC.

~~~
ryanflorence
Go ahead and [do this horrible thing], it's not _that_ bad.

> especially given the still-crude state of JavaScript debugging tools in
> general

I feel like people don't know how to use web inspector...

There will never be native CoffeeScript, you will always debug the JavaScript.

~~~
chc
> _Go ahead and [do this horrible thing], it's not _that_ bad._

Sure. Let me insert a few things that can have really bad side effects that I
still think you should do:

    
    
      • Leave your house every day (car crashes ROFLstomp homicide as a cause of death)
      • Eat food (most foods have some ill effect on your body)
      • Write some code in C (it's a very unsafe language, but sometimes necessary)
      • Use a computer (hurts your eyes and causes carpal tunnel syndrome)
    

Long story short, everything looks horrible if you only look at the bad parts
of things.

> _I feel like people don't know how to use web inspector..._

You're right, many people don't. I'm not one of them, but I encounter them all
the time. That kind of thing is still relatively new, so it's hard to blame
them as much as pity them. And of course the Web inspector isn't there outside
of a Web browser context.

> _There will never be native CoffeeScript, you will always debug the
> JavaScript._

I never said there would be native CoffeeScript; I meant they will support
source maps for alternative languages. Unless the CoffeeScript compiler is
_introducing_ bugs into correct code, being able to get error line numbers in
your CoffeeScript file will mean that you mostly _won't_ have to debug the
generated JavaScript.

~~~
ryanflorence
Source maps will be helpful, but I still can't put a break point in my coffee
script from the browser.

~~~
jeswin
Assuming the coffee script files are accessible over a url, wouldn't that be
possible with a Firebug extension? Which basically maps the break point to JS.

------
peter_l_downs
> You feel pictures and symbols, you feel the relationship. > one !== two >
> isSet || isDefault > > one isnt two > isSet or isDefault

I agree, but it's important to note that pictures and symbols are only felt
because the relationships have been so well defined in the past. I'm not a JS
or CoffeeScript developer (I use python and C mostly), so "!==" is much less
clear than "isn't".

------
exogen
A style guide becomes very important in a language like CoffeeScript where (a)
there aren't established conventions for the language yet like Python's PEP-8
and (b) excluding unnecessary syntax is very, very tempting.

No parens or braces necessary? Don't just omit them everywhere! I was reading
the source code for batman.js (written in CS, after having written quite a bit
of CS myself), and some lines were absolutely baffling. It took way too much
work to parse.

I've started building up a personal style guide. The most useful parts for
maintaining readability are probably:

\- Always keep the parens for function calls, possibly excepting oft-used
functions that are only being called with one argument. (e.g.
document.createElement 'div'; parseFloat '10.5')

\- Always keep the braces for object literals when used in an expression (e.g.
as an argument in a function call); omitting them in a simple assignment is
OK.

------
Andi
I use CoffeeScript in nearly all my JS packages now, and I like it a lot. But
I do not like how many people use it. I use only a subset of the features. The
most important aspects are: short function syntax, implicit vars, short object
syntax, function binding to this, @. I always use brackets when calling
functions, because you need to use them anyway, when you do not pass any
arguments. Omitting brackets makes CS nearly unreadable. CoffeeScript is a big
win for whatever I am doing. The resulting JavaScript is more stable since CS
removes the possibility of a lot of flaws and giving developers the best parts
of JS. On the other hand, you still need clear and constraining guidelines to
manage complex projects. But you need that in any language and framework. It's
not just a necessity in JS development. Thank you, Jeremy. It pays off!

------
dmauro
The debugging problem is definitely the biggest strike against CS, so it's
weird that most of the article focuses on stylistic options (all those parens,
brackets, and ampersands are optional!).

I'm still feeling CS out in terms of what style works best for me (for
instance: should I always wrap arguments in parens so that all function calls
have parens following them?) but it's nice to have that flexibility and be
able to find what I think is readable and clean. For instance, I prefer '=='
because it parses better at a glance, but I find that 'is' is much faster for
me to type. :/

Also the white-space argument meaning it will always be compiled is not
necessarily true. CS's brevity over JS would probably make up for the
significant whitespace difference.

------
YmMot
I think this article is a mix of fair criticisms but at points lapses into a
lot of hand waving. At points it devolves into "This is confusing/non-
intuitive if you don't know CS" and "This is not the way I like to do things".

I find the proposition that porting a library (no matter the size) gives you
"as much experience as anyone" pretty dubious. It's clear the author has some
experience with CS, and I wouldn't discard out of hand the input of someone
who had only used it for 5 minutes...but I found that particular statement a
bit dismissive of people who have been using CS for a long time on a lot of
different projects. Too often people confuse the "getting comfortable, I
basically know whats going on here" phase of learning a language with
"knowing" that language...which is really more "I understand this on an
intuitive level".

I found the "We Process Images and Symbols Faster than Words" section
extremely dubious and strikes me as very hand-wavy. I see what the author is
going for, but it's a completely false analogy and their point is flawed to
begin with.

They're trying to compare the acquisition and understanding of _new_ concepts
vs the recognition of an already known pattern, entirely different things.

Also, the author is essentially cheating, because they are talking about
conveying inherently __visual __information using pictures. Showing someone a
picture of a circle and saying "this is a circle" does __not __convey what a
circle __is __, it conveys what a circle __looks like __(or perhaps, it does
explain what a circle __is __, but only visually) which is to be sure useful
for some purposes. However, it gives them no inherent understanding of how to
properly construct a circle, or what it's relation is to other shapes (such as
a line) geometrically (say compared to a triangle which could be called any
three non-collinear points).

With the baby picture, again...I see what they are going for but I think it
just doesn't actually support what they are trying to assert. Evoking an
emotional response is not the same as passing knowledge, and it doesn't strike
me as a good objective to have when writing code. Sure, show someone a picture
of a baby and they will have an emotional response. However, they will have no
idea who the baby is or why you are showing them the picture which would
probably be more useful.

All of this does very little to support their assertion that "&&" is somehow
more of a symbol and is more visually rich than "and", something I find
dubious even disregarding the poor examples. Letters are symbols themselves
and "&&" is just as much a "word" as any other, though admittedly more
visually distinctive. With syntax highlighting, I would say that there is no
objective difference between "&&" and "and".

"That is verbally readable code, but it’s not very comprehensible"

I'd say that less the fault of CS, and more the fault of the fact that the
algorithm they are expressing in it doesn't make any sense:

    
    
        wash plate, brush, sink for plate of dishes when plate.dirty if meal.status is 'done'
    

This is not a valid construct. By using "of" you are iterating through the
keys of dishes, which will inevitable be strings. You later check the dirty
property of the key (string) which will surely not exist. You need to either
use in or less likely, access them as dishes[plate]. (I'd assume dishes in an
array, in which case a loop is more idiomatic and safe than for-in)

Fine, probably an honest mistake. Sure, I just felt the need to point it out,
though I think it does _potentially_ suggest that the author is not yet at the
"intuitive" level of knowing CS. You are going to have problems like this in
_any_ language where you do not yet fully know it, JavaScript included.

Even excepting that, the algorithm doesn't makes sense. You're cleaning your
sink and brush after washing each plate? Doesn't make much sense. I suggest a
more realistic version:

    
    
        if meal.status is done
            wash plate for plate in dishes when plate.dirty
            wash brush, sink
    

The author makes a couple points about their original comprehension; how it's
densely packed, and I think this largely untangles them. It puts the most
important predicate first.

You don't need to know immediately that you are dealing with the dishes
array... The code is composed of discrete "pieces" and each depends on the
others. I think it's arbitrary to say "oh I need to know I'm iterating through
dishes first thing". It's just as useful to say "ok, I'm going to be washing
something, a plate...". That provides a context for everything else. The fact
that it's a comprehension is pretty obvious immediately so it's just a case of
deconstructing it.

So overall I find this a bit of a straw man. It doesn't make sense to begin
with, it doesn't need to be so packed, and it's taken out of context which
dramatically cuts back readability. If you were writing an app about doing
things in the kitchen, the comprehension (even the dense version) would make
quite a bit of sense because the context would make certain things more
obvious. In my code, this section would probably be prefaced with a comment
like:

    
    
        # cleanup
        wash dishes
        wipe counter
        stow utensils
    
    

So the fact that we just spent X number of lines getting dishes dirty, and
knowing precisely what a dish object is in the context of the overall program
i.e. that they need to be cleaned, it would be obvious that I need to now wash
them each in turn...amongst other things.

Now really, I see what the author is going for. List comprehensions get messy
fast. Sure, I just don't see this as a criticism of CS per se and I find the
example poor.

Remember, just because CS offers extreme conciseness doesn't necessarily mean
you have to use it. I'll admit CS users often make a big deal about
conciseness, and that can send mixed messages...but I would say in most cases
it's about demonstrating that power is there _if you need it_ than saying
_this is always best practice_. The author clearly understand this as they go
on to provide more readable examples, but it bears repeating.

I could similarly break down the "one liner", but I'm running pretty long
already and don't have forever. Again, what is probably a misuse of "of", and
sticking more than is needed in the comprehension. I get the idea that the
point is you can do this, but every language has powerful features with which
to shoot yourself in your foot.

If the author actually found that in their company's code, I most respectfully
suggest perhaps they don't know CS well enough or it may not be their style.
At any rate, it would explain their distaste for CS.

"It’s hard to recognize instantly that I’m actually calling $.ajax"

I suppose, but CS uses juxtaposition to call functions, if you see identifier
__\w __value or identifier __\w __identifier...it's a function call. I would
say, remember CS's golden rule: when in doubt disambiguate. Feel free to add
() to function calls.

I think the next point the author makes it better. I would say that it's just
an unfortunate fact that in many languages some constructs will be ambiguous.
I think CS does a good job of pushing ambiguity to edge/rare cases.

In the author's particular example I would note the point is a bit moot
because CS has implicit return:

    
    
        getUser = (id) ->
            url = "users/#{id}"
            dfd = $.ajax
                url: url
                format: 'json'
                method: 'post'
    
            # return
            url: url
            promise: dfd.promise()
    

In other cases I would refer you to the Golden Rule.

"Now with the fat-arrow, people are encouraged to fat-arrow their way to
oblivion"

I find this a dubious assertion. Stupid people maybe, but I doubt very much
giving stupid people JavaScript will give you overall less problems...just
different ones. At any rate, I don't see any problem with saying a tool should
be reserved for experienced users.

"Therefore it will never really be supported natively, and will always be a
compile-to-JS language, and will therefore always have a terrible debugging
experience."

I disagree. The browsers are working on features to make such debugging much
easier. Further, I know a few people working on CS in CS interpreters, so that
if you need a richer debugging experience you could run your scripts through
the interpreter rather than as JS. Granted it will probably never be as rich
as the Developer tools in the browser, but between the two I would say it's
enough.

The author noted they feel the need to throw in a lot of logging in to debug.
I would say this is a style a lot of CS developers I know use, myself
included. I am quite adept with the developer tools, having debugged JS since
the Venkman and Visual Studio days, but I just don't feel the need for that
sort of debugging very often. For me, it's either a syntax error or a problem
with the flow of data through my program. The only time I really break out the
debugger is debugging other people's code.

Editor macros make inserting logs dead simple. A good build process removes
them except when needed. I can appreciate that some people will find this
workflow annoying and a pain, which is fair. I just want to note I find it
works superior for me.

So this is getting long. Despite my objections, I like this article. CS is not
perfect by any stretch, and it's still relatively new. It needs work. It needs
criticism from the trenches. I think most of the stuff in this article is
mostly fair.

However, I find that CS suits a particular group of developers...and for them
it is a very useful tool. I think that a lot of people criticize it without
realizing that really they don't fit into that group.

~~~
ryanflorence
> "I find the proposition that porting a library (no matter the size) gives
> you "as much experience as anyone" pretty dubious"

My intro comes off as though I'm claiming to be some sort of authority, which
wasn't my intention at all. So good call on your part. I just meant "It's not
like I've only spent 5 mins with the language". Lots of folks out there are
dismissing it w/o giving it a shot.

However, I do know the language well at this point since it has a lot of
rubyisms (and I'm alright with ruby) and at the end of the day is just
JavaScript™.

Concerning images/symbols v. words. Like I said in the article, I _feel_ the
relationship when I see `!==`, I don't feel it when I read `isnt`. However, I
went from design -> code, so maybe imagery is a bigger deal to me.

> but I doubt very much giving stupid people JavaScript will give you overall
> less problems...just different ones

Yeah, one of which is not a less-than-optimal debugging experience.

> The only time I really break out the debugger is debugging other people's
> code.

Welcome to my article.

> Editor macros make inserting logs dead simple

I use vim, and I agree. But that's an extra few steps from my JS debugging.
When something unexpected happens, I go straight the console, start adding
break points, watch expressions, mutating data, etc. etc. to find the problem
before I ever get back to vim. People who have always console.log'd will
probably not get as frustrated as me. I feel like I'm limping.

Thanks for the criticisms. For me, the imagery is a big deal, it's not hand-
waving, it's my true experience, and that of others I've talked to. We all
have different minds.

~~~
YmMot
Sure, likewise it's not my intention to write you off, you clearly have some
good points based on real usage... I'm just trying to contrast your experience
with people who have used it even longer still.

> Like I said in the article, I _feel_ the relationship when I see `!==`, I
> don't feel it when I read `isnt`.

Sure, I think that's fair. The point that I'm trying to make is that I think
this is _subjective_ based on your own personal background/brain/whatever
other nebulous factors.

In your article it could be taken to sound like you are making a case that
there is some neurological reason that "!==" is more readable, and I'm not
prepared to accept that without some more substantial evidence.

I think I get where you're going, you're just trying to draw comparisons...I
just want to add that those comparisons are somewhat nebulous and should not
be taken absolutely.

> Welcome to my article.

I didn't get a chance to expand on that point because of space limits. What I
mostly mean there is once you're in someone elses code, as far as I'm
concerned it's basically all bets are off anyway. At this point when debugging
other-code it's often JS, so the point is moot anyway. However, even when it's
CS I don't find debugging the JS directly very difficult because it's clear
enough for that purpose. Usually it's some issue like a value is not being
coerced properly, or arguments being passed in the wrong order, and those are
pretty easy for me to nail down with a debugger even if the source is a mess
of compiled JavScript...then it's easy to fix it.

Re: debugging, I think we are on the same page. We have different styles.
Yours is somewhat crippled by CoffeeScript. It may get better in the future,
it may not. I just wanted to say I feel no such impediment.

> it's not hand-waving

My main objection is your examples. Like I said they could be construed as
making a more scientific-objective case, rather than a more philosophical
subjective one.

------
samgro
I just spent my entire day tracking down a missing "var" that caused a bug
only in Internet Explorer. I haven't written any assembly code since college,
and I hope to reach a day when I never have to write or maintain native
Javascript again.

~~~
zackattack
You can set up your IDE to automatically run your code through JSLint or
JSHint, which will detect such errors.

------
kristopolous
what about these reasons:

1\. It's trendy. Snooty programmers use them. 2\. It's hyped. Annoying masters
of hyperbole won't shutup about it. 3\. javascript is already easy to write,
easy to read, easy to use, and well understood.

But really it's because I despise hype at such a deep and fundamental level;
it leads people to being impulsive and emotional; making decisions based on
personal reasons rather than finding the right tool fo the job.

countless times i've seen people work significantly longer and harder with the
hype technology then if they had just been solid project managers and made
good decisions regardless of what is being currently blogged about.

other times i've had legacy systems that were built in the super-trendy tech
of yesteryear that was a fly-by-night and nobody uses any more ...

sometimes you will have managers for instance, that wlil request something
like perl code to be rewritten in ruby or some other rearranging of the deck
chairs kind of activity. It's a complete and utter waste of time. I'd rather
go home and click on all those nsfw tags ...

so yeah, no freakin' way; unless there is native support, it's been around for
a few years, and there is actual real solid evidence that it doesn't suck
(extra time that is) for a similar goal.

~~~
roestava
In other words, you find it more advantageous to be a late adopter, which is
fine as well.

Letting the market to select the tools you'll be using seems like a standard
approach to most people.

Early adopters can be such trouble makers. All tools bring tradeoffs with them
and many times early adopters don't anticipate them all.

------
ghc
Pythonista and Haskell hacker here. Everything he hates about Coffeescript is
what I love about it, minus debugging. My debugging workflow looks entirely
different (and more efficient) than his, however.

While I can't say for sure, it reminds me of the days where Java programmers
would try Python and complain that it was harder to write Java code in Python
than it was in Java (esp. with getters and setters).

~~~
phren0logy
Can you please give some details about your debugging workflow? I'd love to
know what works well, as I've been a bit nervous about making the leap to
CoffeeScript for more than just goofing around for this reason. I write a
little Python, but I'm not great with JavaScript, and this seems like a
barrier.

------
cpher
What are your experiences writing CS _on top_ of another well-established
javascript API framework, e.g. Dojo. I do a lot of work with ArcGIS Server's
Javascript API, which is based in Dojo. I also mix in Jquery when needed
(because I prefer it over Dojo). So, would CS be a benefit in these
situations, or just muddy the waters?

~~~
ryanflorence
It's totally natural. So if you prefer CS don't let using a third-party lib
change your mind.

------
MatthewPhillips
My biggest problem is that because it lacks firm rules in a lot of area,
CoffeeScript is a language that is not always intuitive. With JavaScript it's
pretty simple to know the rules; they are completely uniform. Not so with
CoffeeScript. Here's my biggest gripe:

    
    
      greet = (greeting, person) ->
        "#{greeting} #{person}!"
    
      greet "Hello", "world"
    

That's simple. A function that takes 2 parameters, separated by a comma. But
wait, here's another:

    
    
      longRunning = (onsuccess, onerror) ->
        dosomething (e) ->
          if not e.error? onsuccess() else onerror()
    

And the implementation:

    
    
      longRunning
        () -> "Yippee!"
        () -> "Oh noes"
    

A function with 2 parameters, this time separated by a carriage return, not
commas. How would one know that intuitively? That some times functions
parameters are separated by commas and some times by carriage returns? Or that
some times function calls have to include the () (when they have no
parameters) and some times they don't (when they do have parameters)?

I'm sure these things become second nature over time, but learning them will
result in a lot of trips to StackOverflow as you wonder why your code doesn't
behave as expected.

~~~
jashkenas
One _wouldn't_ know that intuitively, because what you wrote:

    
    
        longRunning
          () -> "Yippee!"
          () -> "Oh noes"
    

... is not valid CoffeeScript. I'm not sure where you got that from.

Ideally, you'd write it:

    
    
        longRunning onSuccess, onError
    

Or, if you really wanted to use two inline functions instead of local
variables:

    
    
        longRunning (-> "Yippee!"), (-> "Oh noes")

~~~
MatthewPhillips
Thanks. A more realistic example would, I suppose, look like this:

    
    
      longRunning (->
        ###
        bunch of stuff happening for success
        ###
      ), (->
        ###
        bunch of stuff happening for failures
        ###
      )

~~~
jashkenas
Yes, that'll work fine, as will this, if you prefer:

    
    
        longRunning ->
          # bunch of stuff happening for success
        , ->
          # bunch of stuff happening for failures

------
rayiner
The "symbols are more comprehensible" thing is a bunch of pseudoscientific
mumbo-jumbo. Not the least of all because 'and' and '&&' are both obviously
symbolic, just with different symbols.

------
dreamdu5t
JavaScript looks better than CoffeeScript...

------
pacomerh
Also, talking so much about using it or not adds another layer of complexity
:)

------
iambot
That was a brilliant article, the most complete honesty about coffeescript
that actually makes sense. After reading it I really felt like coffeescript is
cool. but you know what he's got something there. he really does => I'm going
to stick to JavaScript ("See what I did there"). thanks;

------
latchkey
It took me about 3 months of intense CS usage to really get the hang of it.
I've written a good 20-30k lines of CS so far for my application, so I've
developed a lot of good practices since I started. Now, I can't imagine
writing 'pure' JS ever again.

I tend to avoid a lot of the one-line comprehensions for the reasons
documented in this article (they get difficult to 'parse'). I also tend to
write in a more of a Java style, mostly because of my background is in Java. I
tend to put (parens) around a lot of function calls so that I can see it is
still a function. Sure, CS can be abused to the point of being barely able to
read, but that can be said of any language. Having standards and code-review
with your co-workers kind of negates that issue.

Debugging can be a bit of a pain since you have to find the line number out of
a big file. I think this will go away if/when browsers natively support CS.
I've gotten good at naming things so that they are easy to search for in the
developer tools. That makes finding the right line to put a breakpoint on a
lot easier and faster. If need be, I'll throw a console.log('here') in there
and search for that too. Context switching between CS and compiled JS takes a
bit of getting used to, but it isn't really that big of a deal. I'm already
context switching between Java, HTML, CSS, json, etc... what is one more?

The fat/thin arrow thing took a while to get used to, but now it makes perfect
sense. The change they made (too quietly, imho) in 1.1.3 to not use __bind so
much anymore really helped with comprehension. Now I can see the var _this =
this in the compiled code and things make more sense to me now. It also helped
performance and made me worry less about using it. In most cases, it is safe
to just fat arrow things now so it really isn't that big of a deal.

In terms of workflow, I found it very important to integrate it in with my IDE
so that every time I save a file, all of my CS is immediately compiled to JS.
[1] As a result, I don't see any overhead with the compilation phase of
things.

Being able to declare 'class'es and constructors has also been really great
for compartmentalizing my code. Yes, it is possible to emulate all of this in
JS, but I find that a lot more difficult to manage. I do wish there was an
'import' statement though. Right now, I hacked that together with the way I'm
using LabJS.

In the end, is CS a significant improvement over JS? I think so. Just looking
at the compiled output of CS, I couldn't imagine myself writing all of that JS
code and not making a ton of mistakes (ie: === vs. ==, nesting of brackets,
this binding, etc). People say there is a lot of boilerplate in Java... so,
when I use CS, I feel that way when I look at the compiled JavaScript.

[1] [http://stackoverflow.com/questions/6645640/integrating-
coffe...](http://stackoverflow.com/questions/6645640/integrating-coffeescript-
with-eclipse/7507987#7507987)

~~~
ryanflorence
> if/when browsers natively support CS.

They won't, and source maps are not native support.

Check out AMD with RequireJS (make sure you optimize) for your "import" stuff.
I haven't incorporated optimization yet for the project, but you can see how
it works with my snackJS project <http://github.com/rpflorence/snack/tree/amd-
coffee/lib>

~~~
latchkey
Thanks Ryan. I've looked at the RequireJS/AMD import stuff and it seems really
over engineered for what I need. I feel like there is too much declaration
going on. For now I think I'll wait to see what else people come up with along
these lines.

~~~
ryanflorence
Well, AMD is essentially a CommonJS format, so this is what "people have come
up with" for the browsers until real modules show up :)

<http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition>

~~~
latchkey
Thanks for the pointer, I made sure to read it. What I don't like about it is
having to 'define' all the modules that I'm going to use. That is just too
error prone.

I'd rather just create a CS class in a file and include the entire file when I
need to. More similar to the way that an import statement works in Java.

For now, as I already mentioned, I'm simulating import style functionality
with LabJS, which works great. While not perfect, it allows me to async load
everything I need as well as minimize the amount of data on the wire. Here is
a description of what I've done...

[http://lookfirst.com/2011/12/optimizing-your-javascript-
deli...](http://lookfirst.com/2011/12/optimizing-your-javascript-
delivery.html)

------
ccanassa
CoffeScript just adds more complexity into a already complex problem.

------
johnx123-up
Note: This page is crashing my Chrome

------
andyl
All I can say is, I'm way more productive with CoffeeScript than I ever was
with JavaScript. Debugging can be a pain. But I'm using Jasmine heavily, and
finding that a steady dose of TDD eliminates most of the debugging
frustration.

------
PLejeck
Some languages are designed for professionals to comprehend easily at a
glance: these languages use symbols instead of words, use brackets effectively
and don't rely too much on whitespace.

Other languages are designed to be easy for anyone: these languages use
English as inspiration, using whitespace instead of brackets.

CoffeeScript has a place, but not in production. It belongs in the classroom,
to help those wanting to learn an easy language to program in. Ruby, I
believe, belongs there as well.

Languages like C, C++, PHP, JS, etc. are all designed for production. They may
not be pretty to look at, but they're easy to comprehend at a glance.

It's all a question of what learning curve you're aiming for: the learners
curve or the advanced curve.

TL;DR - tradeoffs: learn them.

~~~
jnbiche
Taking this argument to its logical conclusion, Perl would be the ultimate
language for 'professionals' to use, since it's full of shorthand symbols. And
it's true -- if you wrote the code, Perl is very easy to scan. If you didn't
write the code, however, Perl is not always so easy to scan.

Which is exactly the point of Ruby, Python, Coffeescript, and other similar
languages. I´ve heard it said that on average, only 20% of programming is
writing original code, and the rest is maintaining other people's code. For
this reason, Ruby, Python, and Coffeescript are much easier to maintain for
most people than JS, C, Perl, PHP, etc.

Personally, I know both JS and Coffeescript well, and have actually done much
more work in JS over the years, but the first thing I do now when I get a
third-party Javascript program is convert it to Coffeescript (using
js2coffee). I can read and understand Coffeescript about twice as fast as I
can Javascript, even though I started working with Javascript in 1998.

~~~
PLejeck
There's this thing, it's called "balance"

