CoffeeScript Oddities

I really want to use CoffeeScript, a cleaner syntax for JavaScript. Unfortunately, there are too many inconsistencies and oddities that I find frustrating. The main problem is that CoffeeScript considers whitespace to be significant, but the implementation doesn’t handle it well. I guess the CoffeeScript community sees these as features instead. Here are some examples:

Coffeescript is easily confused by whitespace. Of the following expressions, all work as expected except the last one. It thinks the last one is a function call, where “a” is the function and “+b” is a parameter. I don’t know what “+b” means. Most parsers would look for a left-hand side for that expression.

x = a + b    # Normal addition
x = a+b
x = a+ b
x = a +b    # Parses as "x = a(+b)", thinks "a" is a function. 

Coffeescript has a nice syntax for closures, similar to C#. However, it is again confused by whitespace when passing functions around.

compose (x) -> f(x), (y) -> g(y) # Parse Error: confused by comma 
compose (x) -> f(x)  # Parse Error: Still confused by comma
  , (y) -> g(y)
compose (x) -> f(x)  # Works! It finally parses the comma correctly. 
  (y) -> g(y) 
compose ((x) -> f(x)), (y) -> g(y)   # Works! Wrapping in extra parens helps the parser.

Comprehensions can either return a collection or a value depending on subtle differences in the syntax.

r1 = e for e in l     # (1) Turns into FOR loop with "r1 = e" in the body
r2 = (e for e in l)   # (2) Each value e is pushed onto a 
                          #      collection, behaves like map. 
f1 = () -> e for e in l    # (2)
f2 = () -> (e for e in l)  # (2)
f3 = () ->            # (1). Adding another line to the function 
    e for e in l       #       changes the behavior of the loop!!
f4 = () ->            # (1)
    (e for e in l)  
f5 = () -> e for e in l    # Parse Error: The parser doesn't 
    e                          # handle whitespace well. 

Coffeescript does not allow you to define variables with “var” as in JavaScript. It generates the “var” declarations in the correct lexical scope. But it can get confused with names and doesn’t (AFAIK) have a convenient way to tell the compiler what to do. Since JavaScript’s namespace is a wild mess, defining variables correctly is quite important.

a = 1    # Defines a in global scope
f = (a) -> a = 2    # "a" refers to parameter
g = (x) -> a = 2    # "a" refers to global 
h = (x) -> var a = 2  # Parse Error! No way to create a new "a" in local scope. 

There are other little issues which are a matter of taste, not functionality. For example, if-then-else statements are weird. It reserves the “then” keyword for one-liners, but doesn’t use it for normal if/else statements. Or with

x = if cond then val1 else val2 
x = if cond

If JavaScript continues to annoy me I may fork CoffeeScript and patch up these problems for my own use. On the other hand, scheme2js might be a winner.



  1. Trevor Burnham

    The `a +b` thing has been discussed a lot. Unfortunately, `+b` is a handy way of converting `b` to a number in JavaScript, so treating `a +b` as `a(+b)` is really the only sensible thing for CoffeeScript to do (given that parentheses are optional).

    I was taken aback by `r1 = e for e in l` vs. `r2 = (e for e in l)` at first, too, but I’ve come to terms with it. The rules are consistent: Everything left of `for` is a single expression, and `for` loops return a list of their results. That’s it.

    The approach to scope should be familiar to folks coming from Ruby or Python. The idea is to avoid confusion by preventing the existence of an `a` with global scope and an `a` with local scope (shadowing the global). Maybe shadowing from function arguments shouldn’t be allowed, either.

    I hope you’ll continue to use CoffeeScript in the future. There are compromises, to be sure, but it’s a very powerful language that stays close to JavaScript’s semantics.

  2. ayqazi

    Like you, I do not like indentation being used to define blocks (which is probably what you meant by ‘whitespace is significant’).

    The second thing I do not like is that, if a person starts coding in CoffeeScript and uses it in preference to Javascript, what happens when they venture into the wild world and encounter Javascript? The last thing I want to do is train a developer in CoffeeScript, then they encounter some Javascript somewhere that they have to read and debug, and they end up making elementary errors like defining global variables without ‘var’ because they were never taught to do this from the beginning (never taught = “never had it hammered into them so it actually stuck in their minds”). Not everyone is a grade A developer, and thus can’t be trusted to ‘do the right thing’ without lots of training and practice.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s