Variables – Use Case for Shadowing Variables

closurescoffeescriptscopevariables

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
  null

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

Best Answer

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
    null

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

Related Topic