147 comments

[ 3.7 ms ] story [ 198 ms ] thread
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.
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
Answer to what? What's wrong with Javascript in the first place?
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/

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.

Nothing or everything. It depends what your expectation is from a modern programming language and the size of the project you're working on.
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%

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.

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.

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.

I agree there something to the timtowtdi axis.

However:

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

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.

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

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.

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 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 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.
(comment deleted)
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...

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

(comment deleted)
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?
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
           36
         else
           45,
       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
           36
         else
           45
       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`.

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.

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.

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.

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

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.

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

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

Rather than downvote, I'm going to comment.

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

    func 5,
      val: 10
      event: (e) -> 
        if e.something then 36 else 45
Then, for sure, Clojurescript is the answer.
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

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.

Who said it was?
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.

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.
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.
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.
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 don't know CoffeeScript, but this syntax is common in Perl.
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.

with:

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
        element.setValue
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.

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

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
           36
         else
           45,
       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.
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)

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.

LiveScript fixes scoping and adds a ton of other nice features including let and const variable declaration keywords.
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.

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.

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.
> 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.).
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.
I think the death-knell was that you didn't want to bother learning CoffeeScript so that you can actually make an informed decision.
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.
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/

>I ... couldn’t figure out how to write the CoffeeScript for the JavaScript I wanted.
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.