One of the things the coffeescript programming language is criticized for is its treatment of variable declarations and scope (example).

The answers to this question (and the blog I linked to above) seem to hinge on the false dichotomy of variables either being able to be shadowed or else be global. In any language with reasonable scoping rules, this conceit seems (to me) to be a non-sequiter. In the aforementioned coffeescript:

foo = 5
f = () ->
  foo = 12 #foo in the outer scope is closed-over
  bar = 3  #binds a name in f's scope

foo #12
bar #undefined because it was bound in an inner scope

So clearly, bar is not global. If the snippet above was itself inside a non-global scope then foo would not be either. It seems to me that shadowing a variable from an outer scope in a language with lexical closure could only possibly create confusion. So why does coffeescript get slammed for removing the possibility? Is there an important use case here I'm missing? Regardless of how one may feel about the rest of coffeescript, this behavior seems desirable to me.

  • I'd guess that it is because most languages allow variables in inner scopes to shadow outer scopes, so this behavior is unexpected for developers coming from other languages. Jan 7 '16 at 18:57
  • @StevenBurnap Yeah but that gets back into the 'why would you do that anyway' part of the question. Like taking goto out of a language with exceptions, gc, and proper control flow: what would you use it for (that's worth doing)? Jan 7 '16 at 19:01
  • 1
    IIRC, C# also doesn't allow shadowing. Jan 7 '16 at 19:24
  • There's an SO question with some opinions on this for Java, which has an (IMHO) very valid reason in the accepted answer. There is also no "false dichotomy" in the question you linked - it clearly states that there is a third way - making variables non-global and protecting them. However it dismisses it based on some personal experience, since this makes some arbitrary variable names, and likely the most common ones, almost permanently reserved (and the answerer had disdain for that)
    – Ordous
    Jan 7 '16 at 20:22
  • @Ordous shadowing is probably less problematic in statically typed languages (variables would have to have the same type), languages that require explicit declaration of variables (nips that in the bud), and languages that lack lexical closure (less confusion about whether a variable is bound in the current scope or closed over from an outer one). I just think in dynamically typed languages with closure shadowing seems waaay more trouble than its worth, even in light of Steven Burnap's answer. Jan 7 '16 at 21:34

The issue with the way you describe it (I don't know coffeescript myself) is that it makes it too easy to break existing code without realizing it. Let's say you have this code:

bar = 5
// 100 lines of code
f = () ->
    foo = 12

// 100 lines of code
print bar

Now you decide that "bar" is a lousy name and you rename the global to "foo". Suddenly all hell breaks loose. Maybe you don't even notice right away, it slips through your tests and hits production.

Now consider other strategies:

Shadowing (C/C++/others) Have locals shadow globals. In this case, the code just runs as is. foo in the local scope does not affect the global scope, so everything works as before.

Disallow (C#) The compiler tells you not to do that. You change the name of one or the other and everything is fine.

Shadow or make explicit (Python) Have locals shadow globals, but let developers make the use of the global explicitly. Again, everything just works as before.

A related use case, for which these same comments apply, is if you pull and existing function, either just copying the code or using some include method, where a local happens to use the name of a global in the new file.

  • That's a good point about introducing the same name later in a different place and accidentally breaking things. Not sure its compelling, but certainly worth noting. Option 3 is what I personally use for coffeescript/javascript, attaching globals to the window metaobject explicitly and referencing them as properties (window.foo). Jan 7 '16 at 21:29
  • C# disallows one local shadowing another local, but it allows shadowing in general. e.g. you can have a local and a field of the same name. (The craziest case is introducing a type called var which shadows the keywordish var) Jan 7 '16 at 22:21

The backlash towards CoffeeScript specifically is likely because CoffeeScript is supposed to be a language that is similar to Javascript; it is advertised as a variation or extension of Javascript. The homepage even says:

The golden rule of CoffeeScript is: "It's just JavaScript".

Javascript developers might be hesitant to try CoffeeScript when the foundational implicit behavior that they have grown accustomed to has been changed.

  • I totally get that, and why that would be seen as something of a 'false advertising' scenario. Some people will always react negatively to changes irregardless of their merits (especially when told that things won't change). But to me that seems to be a good change especially given that it buys you the inability to inadvertently leak globals (by forgetting var), my question is am I wrong? Jan 7 '16 at 22:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.