3 ms·
I'm afraid that this post, while well intentioned, is actually clouding the issue it's attempting to clarify. It demonstrates that CoffeeScript's `do` feature
by jashkenas 14y ago
I'm afraid that this post, while well intentioned, is actually clouding the issue it's attempting to clarify.
It demonstrates that CoffeeScript's `do` feature provides a convenient way to create a new scope for particular variables (a thing only possible in JavaScript via an immediately-invoked-function, at least, until `let` arrives) ... which is true, but is also an orthogonal concern to whether or not CoffeeScript's normal mode of variable scoping is lexical.
In many of the examples in this post:
do (foo = 'outer') ->
do (foo = 'inner') ->
... all of the variables are local to their function, making it a moot question whether the language is dynamic or lexical. Just as in JavaScript:
function() {
var foo = "outer";
function() {
var foo = "inner";
}
}
... it would make no difference if the language had lexical or dynamic scope, because there are no variables present here that would need to reach outside of their enclosing function in order to perform variable lookup.
Lexical vs. dynamic scoping only comes into play when you refer to an external variable. Whether or not that variable is or can be shadowed is beside the point. Putting parameters aside ... In JavaScript, the variable's identity is the closest "var"-declaration of that variable. In CoffeeScript, the variable's identity is simply the name of that variable, wherever it might occur in the current lexical scope. Both ways are lexical, not dynamic.
- epidemian 14y agoAgreed. Maybe an example of how JavaScript/CoffeeScript would behave if it had dynamic scope semantics could help: // In dynamically scoped JS... var f = function() { alert a; } f(); // would throw an error as expected, but... var g = function() { var a = 5; f(); // would now work because `a` now exists. } // The scope of `a` ends here though, so... f(); // would throw again, but if we give life to the dinamically scoped `a` again... var a = 6; f(); // now works! Printing 6 as "expected" (at least after swallowing dynamic scope).
- raganwald 14y agoFrom the vicious flame-fest that precipitated this post: x = 'lexical' acid = -> alert "#{x}ly scoped" test = (x) -> acid() test('dynamic')
- geraldalewis 14y agoAlso, there's a little issue with @raganwald's counterexample CoffeeScript code. Here's a working version: methods = ['remove', 'show', 'hide', 'stop'] for method in methods do (method) -> # *see notes below Frame::[method] = -> element[method]() for element in @elements *As @jashkenas points out, under the hood, `do` creates a new function (and thus a new scope). Invoking `do` with a parameter list (here "(method)") takes a variable from the outer scope and uses it for a parameter name within the newly created scope. So within that new function, references to `method` will not refer to the `method` variable of the loop body, but to the new function's `method` parameter. `do (method) ->` basically compiles to: `(function(method){ ... })(method)`. See https://gist.github.com/3742581 https://gist.github.com/3742581.