Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

FWIW this is how CS works:

  top_level_variable = null

  f = ->
    top_level_variable = "hello"

  f() 
  console.log top_level_variable # prints hello


The concern is that because Coffeescript automatically scopes variables to the scope of their first reference, it can introduce maintenance issues. Consider the following:

    foo = ->
      bar = "woot!"
      console.log bar
This compiles to:

    var foo;
    foo = function() {
      var bar;
      bar = "woot!";
      return console.log(bar);
    };
bar is locally scoped to foo(). Now, 2 weeks later and 200 lines earlier, you come along and define:

    bar = ->
      alert "Holy crap cheese is awesome!"
Which compiles to:

    var bar, foo;
    bar = function() {
      return alert("Holy crap cheese is awesome!");
    };
    foo = function() {
      bar = "woot!";
      return console.log(bar);
    };
Now, all of a sudden, the "bar" reference in foo isn't scoped to foo() anymore, it's scoped globally, and once you invoke foo(), it'll replace the function bar with a string, potentially breaking your app. It's an ease-of-maintenance issue.

This isn't consistent behavior, though. If you define your top-level bar() function after foo, like so:

    foo = ->
      bar = "woot!"
      console.log bar

    bar = ->
      alert "Holy crap cheese is awesome!"
Then you get "correct" scoping (and the outer bar is shadowed):

    var bar, foo;
    foo = function() {
      var bar;
      bar = "woot!";
      return console.log(bar);
    };
    bar = function() {
      return alert("Holy crap cheese is awesome!");
    };
On one hand, it could be argued that this is a "name things better" problem, but on the other, I have to agree that it'd be nice to be able to explicitly scope things when needed. Given that the behaviors are divergent based on what order the variables appear in, I'd say it's confusing enough that a way to explicitly say "hey, I know what I'm doing, I want to shadow any outer variables and declare local scope here" would be useful.


The inconsistency doesn't stop there; `for` variables are specialcased:

    bar = ->
      alert "Holy crap cheese is awesome!"

    foo = ->
      for bar of bars
        console.log bar
      return

    var bar, foo;

    bar = function() {
      return alert("Holy crap cheese is awesome!");
    };

    foo = function() {
      var bar;
      for (bar in bars) {
        console.log(bar);
      }
    };


That makes plenty of sense to me; when do you ever want to leak a for loop counter to an outer scope?


And when do you ever want to leak local variables to an outer scope? Never.

Not to mention that loop counters are no different than other `var`iables in JS.


You do want to sometimes reference outer scope variables from inner scopes, though. The only difference between a leaked local and a properly referenced global is usage semantics.


This is a better explanation of the problem than the blog post. Thanks!


There is some discussion here on why a "bar" variable at top level only affects the scoping of other "bar" variables that are lexically below "bar" in the file, not above it.

https://github.com/jashkenas/coffee-script/issues/1121


Thanks for this! Way better explanation than the blog post :)

Is there anyway to make the scope explicit in coffeescript?


No. That's the crux of the complaint. In plain Javascript, you can use "var x" to scope x to the current scope (and in 1.7, you can use 'let' to scope to the current block, not just to a function), but there's no corollary in Coffeescript, since Coffeescript manages scoping for you automagically. It's a convenience 99% of the time, but the 1% of the time that it's not, it's a giant pain in the ass. If there were something like var/let/local, you could solve the problem manually, but as the Twitter exchange indicated, there is no plan to add it.

The solution/workaround is "use descriptive names and avoid polluting scopes", but the reality of software development is that you're eventually going to cross those wires, and it's going to make you crazy until you figure out what happened.


Yes, create the variable as a function argument.


While that does allow you to use a locally scoped variable (even one that shadows an outer variable), it's still not explicit scoping.




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

Search: