Hacker News new | comments | show | ask | jobs | submit login
Why CoffeeScript Isn't the Answer (walkercoderanger.com)
136 points by jhack on Mar 30, 2014 | hide | past | web | favorite | 142 comments

I used CoffeeScript full-time for a year, both client-side and server-side (node.js). I completely agree with everything here -- it's a great summary, and it describes exactly while I never, ever want to use it again.

In CoffeeScript, ambiguous code is the rule, not the exception. On top of that, things like variable capture and everything-returns-a-value introduce new kinds of bugs. The author says "realistically, the issues I have raised with CoffeeScript don’t come up every day," but in my experience they pretty much did.

But the real kicker on top of it all is that none of the stuff is documented. When you're trying to guess if you should use parentheses or a comma or an indent or a newline or a backslash or what, there are no reference documents to help you. The CoffeeScript home page just has a bunch of tutorial examples which give you an overall idea, but there's nothing rigorous, and the devil is in the details when you start combining aspects of the syntax.

In the end, I'm much more productive programming in JavaScript because I know exactly how the language works, no surprises. JavaScript has its fair share of warts, but you take a day or two to learn them, and then you never need to worry about them again. CoffeeScript, on the other hand, is just endless surprises. And I still felt that way after a whole year of using it at work. It's basically unlearnable -- no matter how much experience you have, you constantly find yourself pasting different versions of a line into the "try" tab of http://coffeescript.org/ until you get one which, through trial and error, turns into the JavaScript code you want.

You completely agree with everything he wrote, after a year full-time? Really?

So you would use curly braces and commas to specify an object, and then be confused when CoffeeScript doesn't get it?

After a year you didn't figure out that its a best practice to leave off the parenthesis in just the outermost function call, but to include them in the other calls on a line to make things clear?

After a year, you didn't realize that with the CoffeeScript scoping rules, you couldn't just throw in a global at the last second without looking carefully to see if it was used somewhere else?

After a year, you still hadn't learned about function binding with fat arrow?

After a year, you still hadn't learned that the existential operator (?) means you don't have to use typeof nearly as much?

Ha! Not necessarily those specific examples, but the overall reaction to it. Here are a couple of other articles which explain the same things:

Section "full of surprises": http://ruoyusun.com/2013/03/17/my-take-on-coffeescript.html


And here's an old HN comment of my own which described a few representative difficulties: https://news.ycombinator.com/item?id=4518892

Also, there's no such thing as a global in CoffeeScript (unless you explicitly specify window.xyz), since everything is scoped to the file. And that's the point -- it's ridiculous to have to "look carefully" at all your code to see if functions further down share a variable name inside of them. In JavaScript, you don't need to worry about that because you know "var" scopes each variable to its function, regardless of whether a higher function or global variable uses the same name. In CoffeeScript, you suddenly do have to worry about that, which is fairly insidious and bug-prone behavior.

Hm.. well you may want to use more precise language in the future, because you said you "completely agree" and that it describes "exactly".

So you are saying that none of those particular issues are problems you are having today with CoffeeScript or were problems for most of the year?

In which case, what problems did you have?

Edit: it looks like in another thread you are pointing out some random and unmaintainable code examples that are ambiguous and saying that its hard to know how they will be interpreted by the compiler. Its hard to know how those examples would be interpreted by anyone, or why you would write code like that and create that problem for yourself.

I used it for about 6 months, and realised that it simply wasn't worth the hassle. Yes, it looks a bit prettier and the destructuring is nice, but it adds a level of ambiguity that just ain't nice.

The lack of explicit scoping is horrible, and the lack of actual named functions is annoying.

The only thing I use now is JSX (when doing ReactJS), or TypeScript when not using JSX, as that adds actual value.

This article proves not that CoffeeScript is flawed but that Jeff Walker doesn't understand how to use it. For instance, his first example is:

    # BROKEN
    func 5, {
       event: (e) -> 
         if e.something
       val: 10}
Anyone with more than a day's experience with CoffeeScript knows that it's much better to express this with the simpler:

    # far better
    func 5,
       event: (e) -> 
         if e.something
       val: 10
Note how just dropping the excessive notation makes the intention clearer while also making the code cleaner.

His example on variable capture neatly illustrates a few of the opinions of CoffeeScript that actually make it far easier to reason about code: don't use global variables, and if a variable has the same name, it should refer to the same thing. It's far more confusing to allow rampant variable shadowing. Code that relies on variable shadowing is simply broken.

His last example shows a fundamental misunderstanding of not just CoffeeScript, but JavaScript generally. Granted `this` binding can be sometimes confusing, which is why CoffeeScript has a fat arrow (`=>`) to automatically capture `this`.

"More than a day's experience" is not really fair.

It took me months to really get used to CoffeeScript, and I certainly left in a few unnecessary commas after the first day.

The rest of what you wrote I agree with.

But I think the problem is that people are dismissing CoffeeScript before they have learned it, just like I did originally.

I now vastly prefer to use CoffeeScript (or rather ToffeeScript these days, but thats another issue) whereas initially I thought that CoffeeScript was a joke.

Then I had to learn CoffeeScript because it was used in a library that I needed to understand.

It was only _after_ I had invested the time in learning CoffeeScript that I could see the advantages. In fact, up until that point that I had learned it, CoffeeScript _was not_ an advantage for me -- it was a liability, because I didn't know how to use it. When you aren't familiar with a language then whatever advantages it may have are more than offset by the fact that you don't know what you are doing.

I think this is a problem that pretty much every new paradigm shares to some degree. It is very difficult for the average person to emotionally get behind the effort to learn a new way of doing things, and psychologically we just aren't wired to make an accurate judgement about whether that will pay off.

Judgments and decisions are actually emotional/subconscious and the rationalization comes afterward.

the minutia of most efficiently optimizing your syntactic sugar to communicate DEEEEP meanings is the most annoying part of the open-source/language community & one of the biggest factors in why i've actually come to like corporate java.

i've been on so many RoR interviews where i am dismissed essentially for not knowing enough of cutesy syntax tricks and yet in the Java + plain ol' javascript projects i've worked on I've been exposed to a muuuuuch wider variety of programming design patterns than i ever was in Ruby-land, to the point where i could care less about the tiny semantics these hipsters spout on about

one of the few new languages i'm interested in working with now is Clojure simply because they cleanly define libs & then don't have all of this obsessive "syntactic sugar" nitpicking. to make a language / code library usable it shouldn't depend on developers going down a rabbit hole of brackets etc. I understand this is difficult to avoid in the "compile to js"/language pre-processor community but it's why I prefer Dart as a solution. It is an attempt at a clean, robust, simple language rather than a repeat of the annoying language evolution process where devs in the know just talk down to those who don't care to commune with punctuation all day

Thanks for clarifying my point, since I was a bit brash.

The argument you make regarding learning a new language is solid, and I think it can also be applied to new libraries, design patterns or even just coding standards. Now that I think about it, the backwards judgement -> rationalization strategy is one of the more pressing problems facing society, and I was guilty of it just as much by judging the OP first and rationalizing second.

Why not focus on his general point: that CoffeeScript does not fix the problems of JavaScript because it introduces other problems?

He obviously knows a lot more than "day's experience".

If you make the argument that he needs to learn to write better CoffeeScript then you're lending help to his argument.

Why not focus on his general point: that CoffeeScript does not fix the problems of JavaScript because it introduces other problems?

I think the point is that CoffeeScript does fix some problems of JS, but introduces complications of its own. It's worth it for some, but not others.

I think that he should at least understand and know the CoffeeScript syntax to argue that it isn't great. If you don't know C, learnt half of it, then moaned that it didn't compile you'd look like a bit of a fool.

In this case, it's logical that a comma doesn't go there. A comma would go after the closing `}`, which is optional (and so are commas in objects). If you don't know the rules of a language, I feel like it's easier to criticise wrongly.

All you did was remove the curly braces and take out a comma that probably didn't compile in the first place though. I don't get what's far better about it.

Technically, Coffeescript should know better than to balk at the braces that is abstracting out when they're explicitly declared. And any compiler is going to groan when it gets to that dangling comma.

I'm well aware of how little I changed. If I were coding this in my style I'd also move the shorter key/value pair up above the function definition, or more likely simply define the function as a local variable elsewhere. It's very rare that I declare function literals within an object literal.

You're right that the comma was the real tragedy. I removed the braces to help illustrate how taking full advantage of the features of the language makes the code stronger. Strictly speaking removing the comma was all that was necessary.

The argument that "you just don't understand" can excuse any flaw in anything.

If someone can reasonably choose to formulate something, and for that formulation to pass static verification but do something totally unexpected, the language is at fault, not the author.

The point is it doesn't pass static verification. It doesn't compile. It's a rather silly thing for the author to argue imho.

Agreed. I was responding more to the assertion that CoffeeScript doesn't have a problem with variable scoping rules.

It does and the consequences are scary.

You're right that the scoping rules in CoffeeScript are unintuitive for someone coming from a statically-typed, declare-everything paradigm. But I'd hesitate to call it a problem. It's a feature not a bug that the same symbol in nested scopes always refers to the same variable. As I said previously, I believe code that relies on variable shadowing to work correctly is broken.

I've been hit by the scoping rules many times, but every time I ask myself why I'm using identifiers like i, j or x to refer to different variables in nested scopes anyway. Names like that should be reserved for only the tightest of scopes.

Is there another aspect of the scoping rules that you're referring to?

I agree that shadowing is bad.

Implicitly scoping variables to their lexically-outermost point of use is a terrible solution, though: changing anything in any outer scope can completely change the meaning of code in all nested scopes. That's really really bad.

A much better syntax would is to require the 'var' keyword to denote the scope of every variable, but reject shadowed symbols at compile time.

You nailed why I like playing with CoffeeScript: it makes me a better JavaScript programmer. Thinking about each line, the variable names, etc. It's definitely not something I would want to use in a rush.

Rather than downvote, I'm going to comment.

I think you could have made your points just as strongly without attacking the author.

That's a fair point. In my haste to reply I made too much of a personal attack. The phrasing I should have used is more like what ilaksh said [0], which really gets to the heart of the matter.

[0]: https://news.ycombinator.com/item?id=7497354

    func 5,
      val: 10
      event: (e) -> 
        if e.something then 36 else 45

It's a tool, that is all.

Ambiguous code is a poorly thought out contrived example with a simple solution.

To me, this:

    eat food for food in foods when food isnt 'chocolate'
Is kind of beautiful and much more readable than:

    for (var i = 0, var len = foods.length; i < len; i++) {
      var food = foods[i];
      if (food !== 'chocolate') {
How is this even an argument?: "One wouldn’t realize it was conditional until reading the end." How do you expect to understand any code without reading it? How do you understand people when they talk without listening? And the whole paragraph is moot with syntax highlighting.

Variable clobbering is javascript's problem not coffescript's.

ECMAScript 6 introduces a syntactic sugar for classes as well as like every single JS framework.

Knowing plain old JS is important, especially for understanding CS. CS is just a tool that some people find useful, I don't really understand the passion or frustration.

Your Javascript example is a bit contrived too. How about:

  foods.filter(function (e) { return e !== 'chocolate'; }).forEach(eat);
Regardless, I disagree that the Coffeescript example is more readable. My brain is much faster at parsing symbols (`(`, `{`, etc.) than english words.

With your JS example, without having to read the words, I know there's a loop, a conditional and a function invocation. I also know that I can safely add statements after this piece of code without worrying it might break some other function (in Coffeescript, I'd have no way to tell if the implied return really mattered or not assuming it was the last line of a function).

With your CS example, I have no way to tell what's going on until I've read the full sentence. I have to read every word and see if it matches one of the many reserved keywords in order to determine if it has a special meaning or if it's just a regular variable.

In Javascript, you have a few reserved words but the list is relatively short and those words are almost always preceded by a line break or a symbol.

Maybe our brains work differently...

I'm obliged to agree. Even the "contrived" example is easier for me to parse given that I have years of seeing "{}[]()" as delimiters.

Not to mention that filter/each functions will get even easier to parse once es6 standards reach the browser (stabby procs, woo).

I don't understand. Because you have been doing something one way for years, a different way is harder and thus worse?

I'm not trying to be inflammatory at all just wondering as this is a reply to my comment.

Agreed, I dig the functional example you posted. Completely personally I think the CS example I posted fits my style more and is a bit terser.

Also the CS reserved word problem you speak of surely isn't harder than learning to program in the functional style. I mean come on. ;)

I agree that using functional style was not fair (comment edited :)). By the way, here's a non contrived CS example directly from CS's source which I find really hard to understand: https://github.com/jashkenas/coffee-script/blob/master/src/g...

  tokens = []
  for name, alternatives of grammar
    grammar[name] = for alt in alternatives
      for token in alt[0].split ' '
        tokens.push token unless grammar[token]
      alt[1] = "return #{alt[1]}" if name is 'Root'
Why is a loop assigned to a variable? I understand that loops are expressions but the intent here is not immediately clear and definitely requires some thinking. That's what I mean by readability (terseness is another thing).

While on the one hand I agree with your overarching point, I actually find the second set of code tells me much more about what is going on.

That might be because I have been doing curly brace languages for a decade but tells me more, Foods is an array, not an object.

The word isnt as a keyword also makes me want to scream inside a little every time I see it:)

That said you are totally right, It's a tool in a category of tools I never really got into.

Ok, so if CoffeeScript is just JavaScript, add the parenthesis. If you need brackets to make a section of code readable or compile to "certain" JavaScript, then add them. Even the programs I work on we add parenthesis, brackets, etc for readability. Use CoffeeScript to increase productivity. Nowhere does CoffeeScript say you must use white space instead of brackets and such. Keep it simple and easy, classes are also nice; I'll be reading those are articles soon as well to gain less of a bias.

There are still two sides in programming, it seems. And interestingly enough it's not necessarily static vs. dynamic or procedural vs functional.

One the one hand you have pragmatic, loosey goosey languages like perl, javascript, ruby, even scala and C#. An important defining characteristic being perl's maxim "there's more than one way to do it".

On the other hand you have what I'd call the "bondage and discipline" languages like python and java. The defining characteristic being "there should only ever be one right way to do a thing".

In my experience people coming from the 2nd world have a harder time living in the 1st than vice versa.

It's not that simple if you go beyond surface impressions and common usage. There are in fact many ways to do the same thing in Java and Python, some better than others. Both languages have escape hatches that can be used to extend the language; it just requires more effort.

Reflection and annotation processors in Java are very powerful tools; see Guice, Dagger, and AutoValue. Creating something like JQuery is awkward in Java, but it can be done; see GQuery. Java 8 will make functional and callback-heavy DSL's a whole lot easier to build.

Python may look like a strict language but it's not. You can redefine just about anything except the core syntax. If you want to make your head spin look into metaclass programming.

Haskell is a weird one; statically typed, but extremely expressive. It's very easy for Haskell programmers to define their own obscure notations and like when reading mathematics, you must understand the definition of every symbol or you're lost.

One interesting dimension is the attitude towards modifying other people's libraries. In Java, it's easy to build something that nobody else can change unless they fork the library and modify the source or mess with the bytecode. But if you build your own, you can do what you want. In more dynamic languages, you can load someone else's library and muck with it at runtime.

I agree there something to the timtowtdi axis.


python's "B&D" principle is more accurately stated as TSBOAPOOOTDI" (There Should Be One And Preferably Only One Obvious Way To Do It) and that's not quite the same as oft quoted (over?) simplifications such as "there should only ever be one way".

Similarly the Perl community TIMTOWTDI's principle has a related variant TIMTOWTDIBSCINABTE (There Is More Than One Way To Do It But Sometimes Consistency Is Not A Bad Thing Either).

> On the other hand you have what I'd call the "bondage and discipline" languages like python and java.

I can't believe you just compared python to java for B&D. Which language forces you to catch ever exception raised?

>> Why CoffeeScript Isn't the Answer

What is the question for which CoffeeScript is a compelling answer?

"I needed to speak to Germans, so I learned French and spoke through a French-German interpreter. Things were occasionally lost in translation and somteimes I couldn't get my point across, but French is prettier. Can I recreate this experience in code?"

"My team can't learn to write `var` or `===`. Can we just learn a new language instead?"

"Indentation speaks to my aesthetic sensibilities, but braces do NOT! What fits my needs?"

"I don't want to use JavaScript. Fortunately, since I never make coding errors, I'll never need to debug transpiled JavaScript. What's the right language for me?"

Seriously, though, what is the problem that CoffeeScript solves?


CoffeeScript obviously solves problems. Its not compelling to you because of status quo bias, and because you don't want to invest the effort to learn it.

The issue with equality is a real issue. CoffeeScript solves that issue.

Braces and parenthesis _do_ become awkward in JavaScript with callbacks. CoffeeScript solves that problem.

You have been able to debug CoffeeScript as CoffeeScript for some time now with source maps. However, debugging the generated JavaScript is not hard for someone who knows JavaScript.

Its cute you link to status quo bias, then immediately state, like a fact from god that "braces and parenthesis _do_ become awkward (...) Coffeescript solves that problem."

It's your opinion that coffeescript solves the callback and parentheses issue. I'd also call your argument a bit of red herring.

... FWIW? I think futures do a mighty fine job of solving callback issues; no coffeescript needed. Design around them, don't make a whole new "dialect" for it..

For callbacks I have found ToffeeScript to be an even bigger improvement than CoffeeScript. You can write code like this:

    e, personJson = fs.readFile! "person.json"
    person = JSON.parse personJson
    matchesLastname = myDB.query! "lastname", person.name
    id = msgQueue.push! { JSON.stringify(matchesLastname) } 
    log.info "Message sent to queue: #{id}"
instead of this:

    fs.readFile("person.json", function(e, personJson) {
      var person = JSON.parse(personJson);
      myDB.query("lastname", person.name, function(matched) {
        msgQueue.push(JSON.stringify(matchesLastname), function(id) {
          log.info("Message sent to queue: " + id);
Why do you believe that it is better to design around serious issues rather than creating a new paradigm?

I have found that the best solutions always involve a new/different fundamental model that incorporates solutions to recurring problems.

I guess I just don't think it's a serious issue. I've found that often when I have an "issue" it's more so my design lacking not the tool (javascript) itself.

What would the code look like for my example using futures in JavaScript?

    .then(function(e, personJson) {
        var person = JSON.parse(personJson);
        return myDB.query("lastname", person.name);
    .then(function(matched) {
        return msgQueue.push(JSON.stringify(matchesLastname));
    .then(function(id) {
        log.info("Message sent to queue: " + id);

That's part of it. What about creating the promises?

that's in there, with the assumption that you're using the promises based node.js api, but if you aren't, and you're using Q, that part looks like this

    var readFile = Q.denodeify(FS.readFile);
which doesn't create the promise. it just wraps the readFile method so that it returns a promise when you call it.

If anything, coffeescript is the status quo. People just assume it's the hip thing to do; that if you're using JS it's because you simply haven't bothered evaluating coffeescript.

What problems do you think coffeescript solves?

I agree with some the things he writes, but others seem blatant absurdities:

> "the + operator is still both numeric addition and string concatenation. That is frequently listed as one of the bad parts of JavaScript. Why no provide separate operators for the two?"

The problem isn't operator overloading: the problem is implicit type coercion.

Having to use 2 separate operators/functions for separate types when writing code, is useful only if types are actually checked at compile time, and the compiler can do inference on them (see the + and +. operators in F#)

If you have a dinamically typed language, you can have sane semantics if you make it so that type conversions are explicit (e.g. Python, Ruby...)

See also: http://james-iry.blogspot.it/2009/03/operator-overloading-ad...

The problem is the combination of the two. You can have operator overloading if conversion is explicit. You can have a converting operator if the action is explicit. But you can't have loose overloading and automatic conversion at the same time without silly defects.

Edit: And you didn't just disagree but call it a 'blatant absurdity' to blame the half of the problem that you happen to like better? Jeez.

I agree, "blatant absurdity" is quite a strong wording. I should've wrote "quite dubious" or the like.

In my defense, I didn't even think of having a language with type coercion and 0 operator overloading (even on builtin types). I never saw such a language, and I'm skeptical that it could work. But it's an interesting take on the problem.

I cannot say why I think that the no-coercion+overloading is the better solution... maybe that's because operators are dyadic, and thus type coercion can be executed on both sides of the operator, and multiple times. While function application is (can be?) sort of monadic (in the APL sense) since coercion/overloading for an argument doesn't depend on the type of the other arguments supplied to the function

(But while writing this, I'm not so sure anymore... at the very least, it could depend on the order in which arguments are evaluated...)

What I think of here is Lua, where builtin types have no overloading and there is a single type of coercion, between numbers and strings. This coercion is only triggered by arithmetic operators and concatenation. Unambiguous and pretty harmless.

(Technically objects can overload binary operators (with no coercion) but it's not very common)

This article only proves that when doing it wrong, CoffeeScript causes problems.

No parenthesis make nested calls unreadable? Simple add parenthesis for the inner calls. Like in any other language with optional parenthesis (Ruby) too.

Too long statements are unreadable? Don't write them. Maintaining an 80 or 100 character line limit is good coding practice anyways.

That's kind of the point of the article: If it's easy to get it wrong in CoffeeScript, i.e. CoffeeScript has its own bad parts, then you're better off just learning to deal with the bad parts in JavaScript directly.

This is not the first article talking about CoffeeScript's ambiguity and readability issues.

It's interesting how CoffeeScript fans almost always decide to blame the programmers for these problems. They said good developers should use common sense and use best practices to make code readable, for example by always using parentheses when calling functions. I hear exactly the same argument in the Perl community.

But reality is that if a language allows you to write bad code easily, people will write bad code, and you will have to read bad code. This is very easy to verify: most CS project on GitHub, starting with the CS code itself (http://github.com/jashkenas/coffee-script) contain a lot of bad ambuigous uses of the language. A very similar thing happens with Perl code.

Programming language design is not only about making it easy to write good code, but also about making it hard to write bad one.

It is hard to argue, however, that Javascript (the thing Cofeescript purports to improve) doesn't "allow you to write bad code easily" or "makes it hard to write bad code". I have avoided Coffeescript and probably will continue to do so, but it seems to at least try to make it a bit harder to write bad code, albeit not getting all the way there apparently.

I do have some frustrations with CoffeeScript as outlined here - I find the unless keyword infuriating because it forces me to read backwards:

    a = 123 unless b == 2
"OK, so a is set to 123. Oh, unless b is 2. That's annoying"

That said, my answer is to just not use the unless keyword. If you don't like CoffeeScript classes, you don't have to use them. IMO you could write CoffeeScript using only the kind of functionality availabie in vanilla JS and it would still be a preferable experience.

I really like that syntax, I think it reads well.

Of course, I've known Perl for 20 years, so that might have something to do with it. :-)

Pops head down in to a rabbit hole ...

I find your code reads naturally enough forward. Your abstract brief example makes it no big deal to me which way round it goes.

One issue is "end weight". Let me slightly doctor the examples in http://perl.find-info.ru/perl/028/perlbp-chp-2-sect-16.html and ask you to compare:

When, after long nights of hacking, in horrible dreams there come to me damnèd souls responsible for ANSI C++, I run screaming.


I run screaming when damnèd souls responsible for ANSI C++ come to me in horrible dreams, after long nights of hacking.

If I were writing one of the above two sentences, "end weight" consideration might lead me to write the latter.

If one applies these principles (left-to-right sweep and "end weight") to writing and reading of programming language statements one arrives at features such as the 'unless' keyword and the benefits they supposedly confer on writers (expressivity) and readers (ease-of-reading).

Let's make it a less abstract example first

    element.setValue value unless no_change
I'd read this example as: In most cases, we set the value of the element. However, sometimes there haven't been any chances, so there's no need to set any new value.

Of course, I could write it as, for example

    if change
but to me, however, although the end result is the same, that second example does not convey the same message to me as the first. In the second example, I'd interpret the normal situation as there being no change, but if there is one, update the element.

I think that's also the reason why I like programming in ruby. I feel I am able to better express my understanding of the situation in code than I could if these seemingly syntactical sugary bits weren't there. I also think it is mostly a matter of personal preference.

I don't know CoffeeScript, but this syntax is common in Perl.

Am I the only one astounded that we're still having this conversation? The fact that it's still around shows me it has indeed been "the answer" for some. The fact that it hasn't become ubiquitous is plenty of proof that it also is not a one size fit all solution, as if any solution is.

I wonder what the author thinks of GorillaScript [1].

[1]: http://ckknight.github.io/gorillascript/

Very interesting! I was nodding along through the first dozen syntax features or so, which seemed much more obvious and well-chosen than CoffeeScript's, and then they just kept piling on... Promises? Macros? Generics??

I won't prejudge GorillaScript, but if someone ever makes a language like this that exhibits both good taste and a little more restraint, it could get wide adoption.

"CoffeeScript isn't the answer because I don't understand how it works."

This seems to share many of the same things of CoffeeScript I've had. I prefer plain old JS. More readable, unless you're looking at twitter bootstrap code... No semicolons? Such messy code IMO.

I find CoffeeScript very readable, and I highly value readability. The extra verbosity of JavaScript doesn't really help me when I am reading code. I read CoffeeScript code faster than I can read JavaScript because CoffeeScript removes so much of the repetitive boiler plate code and lets you focus on the intent of the code.

I don't really understand the ambiguity argument. From the code examples in the article, I get the impression that the author doesn't really understand CoffeeScript.

I definitely prefer CoffeeScript to good old JavaScript.

I had a lot of niggles with CoffeeScript as well, which is why my compiles-to-JS language of choice is LiveScript[1]. It fixes basically all the annoyances and adds a lot of nice things on top of that. For exmaple, you can write more paren-free code with it and there are more kinds of useful function declarations (hushed functions, curried functions, backcalls).

[1] http://livescript.net/

Mm, most of the issues the article discusses are part of the learning curve of Coffeescript IMO. The real problem I've had (and I still love it for some reason) is dealing w/ JS frameworks. Like, try using Coffeescript w/ Angular or something. It's quite difficult.

Disclosure: I have never used CoffeeScript. However, based on the article, the death-knell against CoffeeScript for me was the variable scoping rules.

With no variable declaration keyword (a la var, my, local, private), adding a variable assignment anywhere could radically change the variable scoping.

I'm done, this isn't suitable for prime-time, time to go somewhere else.

I spent too many years in the 80s working with xBase. I've been shafted too many times by calling a (coworker's) routine that forgot to declare its variables "private", which stomped over one of my variables. (private in xBase is similar to local in Perl 4) To have a language which doesn't let you declare the intended scope of a variable - ugh.

I've used coffeescript extensively for years, and I have never had that be an issue. Not sure if it's because I rarely write a file longer than ~200 lines, or I'm careful about variable names and global scope.

More generally I've found that coffeescript mixes much better with a functional style than with an imperitive one.

This, to me, sounds just like Douglas Crockford when he dismisses all the evils of Javascript as "things that never happen to him". Which is interesting, given that they occur to me and my work mates on a fairly regular basis.

I don't think the gist is that there aren't problems with these languages, but that with a little carefully placed construction tape, you can avoid falling into the large holes.

Yeah, people say the same thing about C++. It's great when you have your own carefully curated subset of the language.... and then you have to deal with other programmers & libraries

The difference being, you can't avoid javascript (if you want to target the browser); you can either write it directly, or use it as a compile target. Each has it's strengths and drawbacks.

These sort of problems crop up a lot more the larger a codebase gets and the more people working on it. Being careful with your variable naming and global scope are necessary to working well with CS.

The biggest problems I find with bad coffeescript that I don't generally find in bad javascript are extensive inheritance hierarchies, overbroad class design, and explicit dependencies.

Generally the same kinds of problems I find with bad ruby/java.

The scoping issue is real, but it's very easy to mitigate. I think the real issue is to make sure you just don't ever use (file) global variables. You should enforce scope with the "do" operator:

  changeValue = do ->
    value = 42
    lastValue = null
    (newValue) ->
      lastValue = value
      value = newValue
That hides the new variables in a closure and they no longer leak to the the enclosing scope. This is cleaner code overall since you no longer have some variables at the top level where you can't be sure of how many functions are using them without searching.

> With no variable declaration keyword (a la var, my, local, private), adding a variable assignment anywhere could radically change the variable scoping. > I'm done, this isn't suitable for prime-time, time to go somewhere else.

So does that mean Python and Ruby are out the window too? It's really never been an issue in either of the three languages.

The problem in Python and Ruby is less obvious because you rarely have big, nested closures. In JavaScript those are pretty common (module pattern, mocha test suites, etc.).

LiveScript fixes scoping and adds a ton of other nice features including let and const variable declaration keywords.

I think the death-knell was that you didn't want to bother learning CoffeeScript so that you can actually make an informed decision.

Phew. I was beginning to worry that a whole month would go by without a blog post about CoffeeScript's deficiencies. I hate it when I write unidiomatic code in a language and then get punished by said language.

Now that I got my sarcasm out of the way, whenever somebody bashes CoffeeScripts variable shadowing they openly show the world that they don't understand how variable scoping should work. CoffeeScript covers up JavaScript's warts. One of those warts is JavaScript's broken implementation of closures. CoffeeScript is trying to help you, don't let your lack of understanding of lexical scope get in its way.

> The declaration of what food is occurs in the middle of the line and doesn’t even look like a variable declaration.

And that's what makes the whole line unreadable. And 'unless' would make it even less readable.

I can understand why people insist on discussing such personal, subjective matters as "readability" or "expressiveness" - I like that too. What I don't get is why do they confuse their impressions with facts and why do they try to generalise based on them. Is it that hard to admit that what's readable to you may be completely unintelligible to someone else?

Comparison of programming languages, outside of some really technical metrics, will always be subjective and preference-based. Discussing metrics as vague as "readability" without even agreeing on what it means is absolutely pointless. Yet so many man-hours go into debates and blog posts, sometimes even books, which cover such issues. It's stupid, straw-man discussion every single time it appears.

I really wish people would stop writing lengthy posts with a sole purpose of informing the world about their preferences. It's not that I'm against people having preferences, I'd just like them stated as preferences, not facts, and preferably only when they are not repeated a millionth time this month.

Edit: also, this: http://joelgrus.com/2013/12/24/why-programming-language-x-is...

> eat food for food in foods when food isn't 'chocolate'

> from the CoffeeScript tutorial...Furthermore, until you finish reading the line it isn’t clear which foods will be eaten.

The thing with typing the filter at the end is, that format has its basis in mathematical notation, particularly in set theory. Using an even terser mathematical syntax/notation, you could write the same expression this way:

    { eat(food) : ∀ food ∈ { foods } ^ food ≠ "chocolate" }
You read that as "the set of eat(food) where for all food in the set of foods, the food isn't chocolate". The notation will be quite familiar to mathematicians, and thus if you have a strong mathematical background, especially in set theory, discrete math, and combinatorics, the CoffeeScript array comprehension feels natural.

See the Wikipedia article on Set-nuilder Notation/Set comprehension, http://en.wikipedia.org/wiki/Set_comprehension.

Here's another example from the Wikipedia article:

    { x | x ∈ R ^ x = x^2 }
This reads as "the set of all x, where x is a real number and x = x^2", which evaluates to the set { 0, 1 }.

I believe there will be a day when converting CoffeeScript to just native JavaScript won't be very difficult, but until that time, it's useful as a way to have neat syntax features without having to wait for browsers to support it. Indeed, many of the features CoffeeScript introduced into the JS developer's mindset are or will be present in the upcoming ECMAScript specifications. We can only assume this trend will continue.

    delayed: () ->
      -> this.model  # isn't the class
Well, that isn't really fair now, is it? You could have used the fat arrow (`=>`) for binding `this` to the class.

With that in mind, I agree with the author in that CoffeeScript isn't the answer, at least not exactly. With syntax this incredibly similar, how far are we from compiling python (with generators, with statements, imports, ...) to JavaScript?

>how far are we from compiling python

I frankly find CoffeeScript nicer than Python. There are advantages and disadvantages, obviously, but whenever I'm writing Python, it makes me long for CoffeeScript.

Going from CoffeeScript to Python (bundled together with going from Node.js to Python) is painful. So many things that CoffeeScript has learned over Python - of all of them, "everything is an expression" rule.

CoffeeScript is more readable than Python.

If you really get familiar with CoffeeScript then you will see that the benefits add up over JavaScript.

If you want a nice Python-like language with import statements and many interesting features that compiles to JavaScript, take a look at Nimrod.

There are a few projects, this is one: http://en.wikipedia.org/wiki/Pyjamas_(software)

This is a bit overly critical. The implicit parentheses are optional, so if it's confusing or ambiguous you should just use parentheses.

    func 5, {
       event: -> 45,
       val: 10}

Is reasonable but

    func 5, {
       event: (e) -> 
         if e.something
       val: 10}

Really ought to be split up for readability no matter what programming language you use. And besides, the only issue is the extra comma causes it not to compile.

To be fair, the `->` vs `=>` (which `this` is `this`?) for class members is confusing. I'd almost prefer class members didn't give you the option and defaulted to `=>`.

The "variable capture" section is overblown, though. You're a lot less likely to run into this issue than the classic JavaScript "I forgot `var` and now my variable is global.

My biggest complaint is actually the implicit returns. Sometimes I forget a return statement but it works anyway because of this feature. Then I come back later and modify the function slightly only to spend a bunch of time figuring out why it's returning `undefined`.

If you write JavaScript in strict mode the probability of incidentally declaring something as global is pretty much zero. Those mistakes can also be properly linted and warned against - which is not possible for CoffeeScript's implicit declarations. And at least I had real-life situations where CoffeeScript's scoping broke code in very subtly ways.

Then, for sure, Clojurescript is the answer.

Clojure is really hard for me to use, coming from a lisp background. The various special forms seem to sometimes want a list and sometimes want a vector and sometimes don't care. I've yet to find a way to keep track of that.

Anyone have a link to something from Rich mentioning why vectors are used in basic syntactic constructs? It's the one departure from its lisp roots that I couldn't figure out any motivation for.

I've never seen any explanation from Rich on the subject, but semantically speaking, vectors used in syntactic constructs are almost universally meant to denote binding forms. Let-bindings, loop-bindings, function parameters and the like all use vectors in the context of binding symbols to values.

I find that, having gotten used to the mental shortcut "square brackets == binding", the distinction makes it easier to read the "shape" of code from a very high level and get a general understanding of its meaning at a glance. YMMV.

Does it have a good interop? Does it require a big change in mindset? These are my questions. (Real questions, I've never used Clojure apart from some basic tutorials)

Yes and yes (it's probably arguable though: you need to export symbols to avoid getting them mangled by the google closure compiler)

But since the author dismissed Dart due to not being "true to javascript", I doubt that he'd be satisfied with it

The example in "Ambiguous Code" is ridiculous - if you write CoffeeScript like that then you have much bigger problems. Also, the part in "Classes Are an Illusion" totally fails to mention the fat arrow `=>`, which solves the main issue the author raises.

However, this part I completely agree with:

> Realistically, the issues I have raised with CoffeeScript don’t come up every day. Ultimately though, they are enough to say we need something better. I hope to share some thoughts soon on what such a solution might look like.

CoffeeScript isn't perfect and we should always be looking for better solutions. So I'm glad that the author wants to add to the discussion. While CoffeeScript isn't the answer, it's probably the best answer we have so far,

Coffee-script is awesome but suffers from it's roots as a preprocessed layer on top .. and that essentially leads to poor overall tool chain support .. I actually enjoyed writing code in it .. debugging not so much .. Would love some of the constructs to make into JS

I have a rule of thumb that coffeescript is never appropriate for code that has to be require()'d by any code written by somebody else than me.

I'll happily use coffeescript, and enjoy doing so, when that condition is met. It doesn't happen very often though.

While it might not be the answer, it has been a very good answer for me. Recently I worked on an Angular project that had a pretty complex data model, and converting the model to CS made the code much more readable. The rest of the app was still in JS, minus a ./models directory which was CS. The other devs found the code very readable also.

I am biased towards Python and Ruby. I think that they are nice looking languages.

Different tools for different jobs. Next time I am on a JS project and I want to model data, I will probably use CS again.

Answer to what? What's wrong with Javascript in the first place?

What's right with it? It's an awful language:

Not being able to import/include library code is bat-shit insane. You can't reliably check the type of things like arrays.

The 'this' value is 'wrong' in callbacks (by wrong, I mean, not what programmers actually need in that instance).

Javascript dates values are 1-based except for months which are zero based - be consistent!

Math.parseInt will produce correct results for 05, 06, 07, wrong results for 08, 09 - don't ASSUME a radix! (unless that radix is base 10).

It goes on regardless in the face of a large number of errors meaning that the location of an error can be much harder to find than is necessary - I believe that fail fast is infinitely superior to 'just muddle through and do something random with that invalid state'

You can't rely on getting decent stack traces out of it on error which makes debugging harder than it should be.

It's easy to accidently add globals.

I'd add lack of types: obviously that's a preference but when 30% of your tests just end up checking what a compiler could have done for you for free, then I say that;s a fault with the language.

That said, I really like array and object literals. It's not all bad. Just... about 86%

For me, coffeescript was the answer to the question "How can I write javascript with python-esque whitespace block formating?" I suspect the author was asking something like "what can replace javascript?"

Coffeescript seems to be more like Perl, where parenthesis are often optional, and meaning is implied by the context a lot of the time.

I like Perl, but I tended to be fairly pedantic with parenthesis and things when writing it. I prefer explicit over implicit. (Though sometimes implicit can save you a ton of time).

I also quite like coffeescript for its "everything is an expression" mentality—it makes functional programming very nice.

The absence of this feature is why me and Python don't get along.

People have documented this many times. It boils down to surprising features of the language.



Ironically - he doesn't it's kind of the whole flaw in the series.

How is JavaScript a minefield? Well, JavaScript has all sorts of pitfalls lurking for the developer. Each pitfall is like a mine in the minefield, silently waiting for you to accidentally step on it. Just like the minefield, JavaScript’s mines are hidden in plain sight. Entire books have been written about all the mines present in JavaScript. Maybe I’ll get into what some of those are in future blog posts.

So then he goes into why Typescript/Coffeescript/Dart aren't the answer to the "Javascript minefield" though he doesn't actually describe the mine's he's trying to avoid. He's not even bothering to setup a strawman to knock down. Its kind of hard for any tool to solve an undefined problem.

A little further down the same post [1]:

Given that a safe path through the JavaScript minefield isn’t enough, it seems like we need a detailed map of the minefield. Many books and blogs have been written to provide that map. JavaScript: The Definitive Guide by David Flanagan is one of the most detailed of those books. The JavaScript Garden is a good place to start learning about the mines online. [2]

[1] http://www.walkercoderanger.com/blog/2014/02/javascript-mine...

[2] http://bonsaiden.github.io/JavaScript-Garden/

Nothing or everything. It depends what your expectation is from a modern programming language and the size of the project you're working on.

The only gripe I share is scoping, and that's fixed in LiveScript. I've started writing LiveScript in a fairly explicit style - for example I use parentheses where they improve readability and I always use curly braces for object literals. Qualitatively I think it's increased the readability of my code way beyond JavaScript. It's nice to have curly braces carry specific meaning instead of being littered all over the place.

CoffeeScript is putting lipstick on a pig. It's pretty damn good lipstick, but still being applied to a pig.

My problem with CoffeeScript has always been the syntax vs. semantics issue. CoffeeScript saw a big opportunity to improve JavaScript semantics and help programmers more easily avoid the JavaScript minefield ("var" and "===" for example), but in doing so decided "while we're at it, let's overhaul the general syntax too".

Gratuitously changing "function" to "->" for no reason other than removing characters seems to introduce more brand new idiosyncrasies than it's worth. If the goal were to improve JavaScript as a language by smoothing over a few of the gotchas, which of course would require a few syntax updates, then I think it would be immensely valuable. (Think SCSS instead of the original "Sass".) But it seems as if the authors were more troubled that JavaScript didn't write like Ruby, so they made a new language that happens to compile to JavaScript. And now I have two languages to choose from, each with pros and cons and their own gotchas, adding more complexity to my decisions when I was hoping for simplification.

I totally disagree regarding 'function'. Good javascript tends to be more functional than imperative. That means using 'function' a lot. Most functional languages use either fun, fn, or lambda, all relatively short words for this because it's used ALL THE TIME.

Shortening it to two chars made sense IMHO. The long form of the word function directly impacts code quality and readability.

If all you want is a sane subset of JS, then all you need is a JS linter. The whole point of the language was more compact syntax.

Shortening lambdas is one of the most important changes because it makes heavy callback/DSL code viable. Exhibit: http://coffeekup.org/.

Now renaming JS's `for (name in obj)` to `for name, val of obj` and redefining `in` to `for x in array` is indeed confusing (coming from other languages I can see how it's better than JS ideosyncratic use of `in` but still confusing...)

The arrows are better because they're shorter, more math-like, and because there's two of them (skinny and fat arrows) that do useful things.

For what it's worth, the arrow syntax is likely going to be in JS at some point: https://mail.mozilla.org/pipermail/es-discuss/2012-March/021...

> Gratuitously changing "function" to "->" for no reason other than removing characters seems to introduce more brand new idiosyncrasies than it's worth.

What idiosynchrasies are you referring to here? Just curious. I love the stabby lambda (for the exact reason you listed, because I am defining functions on every other line).

These pitfalls can be easily avoided by following a styleguide [1]

[1] https://github.com/polarmobile/coffeescript-style-guide

There is still not "answer", and the world is not gonna end tomorrow, in the future maybe will be one but until that day comes i will stick with whatever i find appealing to me at present. For now is CS.

CLOJURESCRIPT IS THE ANSWER! no question about it

The problem I have with clojurescript is i couldnt find any closurescript tutorial that did not involve java.

Let's say i want to start using closurescript,like coffeescript.

i want to do npm install -g closurescript then

closurescript compile myscript or closurescript myscript.

How do I do that?

If closurescript folks want their language to be popular with javascripters i need to be able to do that.

Right now,searching on google,on npm, i did not find any tutorial that did not involve maven or java.You cant expect a nodejs developper to learn maven or install the JVM for the sake of using clojurescript.

coffeescript is popular because it's easy to get started with.You dont even need to install anything,just add the coffeescript compiler to a HTML page.

clojurescript's compiler is written in java. I think there are a few obstacles that keep clojurescript from basing clojurescript purley on javascript.

Nevertheless, if this is all that keeps you away from clojurescript -- too bad. Because it is a great alternative to pure javascript.

There's even a button at the top of the main coffeescript page. It's so very convenient.


npm depends on a javascript compiler such as g8 so how is that different than clojurescript depending on the JVM ?! It's no different at all you're just complaining that you don't like to have to install software before using it which is ridiculous if you want to use powerful software.

what is ridiculous is a compile to javascript language that is not written in javascript itself.

Sometimes I think that most CoffeeScript, ClojureScript, etc. programmers are people who were advanced in other languages before they learned JavaScript. There are quite a few programmers who have no issues with these "bad parts" or "really bad parts" because they cut their teeth on them, and these numbers are growing: Most people now learn JavaScript as their first language. JavaScript already won, and things like CoffeeScript are the last gasp of the old regime.

as someone who coded JS all through the 00 years and still remember the times when we welcomed prototype.js as fresh air and the struggle that was JS coding then - so basically i think i'm the ancient regime - i have to say: no

CS is not the silver bullet - but neither is blind believe that vanilla JS is the best way to code for the web. things change. technology runs in (hype)circles: we welcome the new stuff (i.e. languages), only we see the benefits of the old way, and then we still create new stuff...

As someone from the old regime (cut my teeth on spectrum basic in the 80's, get of my lawn etc etc) I sorta agree.

For years I avoided using javascript beyond wiring little bits of jQuery together because I hated the language but eventually I ran into a project where I could no longer do that and resolved to learn javascript properly.

Many wtf's where had but now looking back I realise that Javascript is a warty language (but then show me a widely used (top 10) language that isn't).

I still don't like it but I don't hate it and I just accept it for what it is.

To an extent it is a Devil you know/Devil you don't thing. The moment one of the JS-first people get bitten by the CoffeeScript compiler (having to indent/dedent something, move a comma, suddenly your code is working ... I think everybody runs into the sort of issues the author described) they are going to go back to JS. JS is such a high-level language already, and the browser vendors and SSJS projects seem focused on advancing it. I just don't see much room in the future for languages like CS.

I agree the other issue with someone like me using CoffeeScript is that first I'd want to really understand Javascript otherwise I'd never be able to trust that I could fix any bugs I ran across, it's another layer of abstraction I essentially don't need.

I disagree with this. This implies that you always view your first language through rose colored glasses. I don't think this is the case. Anectodally, I learned C first and still use it to this day, but I can certainly tell you where its flaws are and when I would and would not use it.

Yes, a beginner might not see the flaws of Javascript up front, but given enough time to become an expert, they certainly will.

Your argument is that because programmers who learned JavaScript first "have no issues" with the "bad parts" or "really bad parts" that means they aren't really issues, or that we should ignore the issues and adopt JavaScript anyway because we don't want people to think that we are old?

Exactly this. I used CoffeeScript when I had hard time understanding JavaScript. Once you truly gasp JavaScript, anything else will just look like a waste of time.

I have a hard time seeing someone who has actually spent some time with Clojurescript making that statement.

That statement has nothing to do with personal experience, and everything to do with unmistakable trends in software development. If JavaScript were a frozen language I would agree with you, but the momentum behind JS is a tsunami.

Livescript or Gorilla are what I would want from a .js precompiler. Coffeescript just removes brackets and readability.

>I ... couldn’t figure out how to write the CoffeeScript for the JavaScript I wanted.

What is the question?


Nice reply!

One little thing I disagree: Syntax is important. A language is an interface for a low level context, and since it's an interface, it does have UX. Syntax is a big part of the UX of a language.

And it's no me that is saying this, it's Crockford: https://www.youtube.com/watch?v=_EANG8ZZbRs

Who said it was?

CoffeeScript seems to be an efficient alternative to plain Javascript. The fact is you can't avoid seeing Javascript completely. Just try debugging in Chrome or any other browsers built-in debugger and you'll know what I mean.


"A witty saying proves nothing." - Voltaire

Now that's ironic.

Applications are open for YC Summer 2018

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