"""
Sorry, folks, but I'm afraid I disagree completely with this line of reasoning -- let me explain why:
Making assignment and declaration two different "things" is a huge mistake. It leads to the unexpected global problem in JavaScript, makes your code more verbose, is a huge source of confusion for beginners who don't understand well what the difference is, and is completely unnecessary in a language. As an existence proof, Ruby gets along just fine without it.
However, if you're not used to having a language without declarations, it seems scary, for the reasons outlined above: "what if someone uses my variable at the top of the file?". In reality, it's not a problem. Only the local variables in the current file can possibly be in scope, and well-factored code has very few variables in the top-level scope -- and they're all things like namespaces and class names, nothing that risks a clash.
And if they do clash, shadowing the variable is the wrong answer. It completely prevents you from making use of the original value for the remainder of the current scope. Shadowing doesn't fit well in languages with closures-by-default ... if you've closed over that variable, then you should always be able to refer to it.
The real solution to this is to keep your top-level scopes clean, and be aware of what's in your lexical scope. If you're creating a variable that's actually a different thing, you should give it a different name.
Closing as a wontfix, but this conversation is good to have on the record.
"""
Missing that Ruby stops scoping variables at a method and uses separate lexical scoping rules for constants thereby avoiding this issue mostly.
class Foo
def bar
"bar"
end
def baz
bar = "foo"
puts bar
end
def bang
puts bar
end
end
foo = Foo.new
foo.baz # => "foo"
foo.bang # => "bar"Unless you happen to embrace JavaScript's functional side and write lots of top level helper functions (in a closure of course after which you export)
shadowing the variable is the wrong answer. It completely prevents you from making use of the original value for the remainder of the current scope.
This smells of static enforcement - strange for a language expounding JavaScript's dynamic nature and an odd departure from "it's just JavaScript".
Shadowing doesn't fit well in languages with closures-by-default
Not sure what evidence this is based on given the heap of great languages with closures-by-default that give programmers more control over scope without introducing goofy constructs like special assignment operators or global/nonlocal keywords.
CoffeeScript breaks the one real form of encapsulation (which includes the power of naming) that JavaScript has - function locals.
In addition, to repeat myself elsewhere in this thread, the goals here are conceptual simplification and readability, not giving the programmer more control over scope. The final result is that hopefully:
someVariable
... more code here ...
someVariable
... more code here ...
someVariable
... more code here ...
someVariable
... in the above code, you can know that "someVariable" always refers to the same thing. With "var", the above code could allow "someVariable" to refer to three different things, each for slightly different sections of the above chunk of code.If you really want three different values, use three different names. In all cases, it will read better than shadowing would have.
That's totally false.
In languages like Scheme, O'Caml, etc you are never prevented from using the original value.
The point is that lexical, aka static scope is all about lexical pieces of code that you fully control, and all their properties are statically apparent, by looking at a single piece of code.
Scheme:
(DEFINE FOO 1)
(LET ((FOO 2)) ... FOO IS SHADOWED HERE ...)
Inside the LET, FOO is shadowed (FOO is "your FOO") and that's lexically, statically apparent by looking at the piece of code.If you don't want it shadowed, and use the global FOO, you just use another variable name. You cannot be prevented from using the original global FOO, because you choose the local variable names you use in a piece of code.
Unless you're using a system in which non-hygienic macros are present and they expand into it...
Javascript seems to have the model "everything you do is global, unless you know better".
I'm not a big Javascript hater, but this is one very sore point.
Although the following examples could become unambiguous with parenthesis, these examples demonstrates how a trivially overlooked ending delimiter further complicated the language. Not only is the intent of the CoffeScript code unclear in the examples below but the slight variation in the CoffeScript, produces radically different output. The CoffeeScript differences are so small it would be easy for someone to add accidentally while editing. Anonymous function passing and function calling in Javascript require no additional wrappers or edits, while in CoffeeScript you must add special case clarity.
http://img542.imageshack.us/img542/7379/coffeescripttojavasc...
How arrogant! You'd think he'd step back for a second and consider the suggestion, but it sounds like he's on autopilot.
See: https://github.com/jashkenas/coffee-script/issues/712 https://github.com/jashkenas/coffee-script/issues/238
Whether he's right is another question. But if you don't like his decision you can use the Coco (https://github.com/satyr/coco) fork which fixes it by introducing := for nonlocal assignment.
It shouldn't take a lot of thought to see why this is a somewhat user-hostile, passive-aggressive approach for a language. If something is ill-advised, the language should actively steer you away from it, not dissuade you with subtle bugs a few thousand lines of code down the road.
I think this scheme would be more workable if sigils or similar conventions of some kind were mandatory for top-level symbols. Then it would be much harder to accidentally wander into this problem. The language he seems to be drawing inspiration from, Ruby, does do this.
I really don't understand why this isn't being fixed: doesn't global by default break encapsulation? I'm probably missing something, but this is the main reason I haven't tried coffeescript yet.
how_many_times_functions_have_been_called = 0
f1 = ->
how_many_times_functions_have_been_called += 1 # refers to top-level scope
console.log x # undefined
x = 1
console.log x # 1
f2 = ->
f1() # refers to f1 at top-level scope
how_many_times_functions_have_been_called += 1 # refers to lop-level scope
console.log x # undefined
x = 2
console.log x # 2
f1() # you can call f1, it's at top-level scope
f2() # you can call f2, it's at top-level scope
console.log how_many_times_functions_have_been_called # 3, refers to top-level scope
console.log x? # false, x does not exist at top_level scopeThere are lots of people throwing in their $0.02 on how the language should work without having joined the mailing list or seen any discussions on the thought process behind its features.
I'm not saying the suggestion made isn't reasonable, but I can understand glib replies like this from the author that don't make too much effort to explain his stance more than 140 characters.
There are dozens of lengthy conversations about this in the CoffeeScript issues, if you'd like to take a deeper look.
Here's how he introduced CoffeeScript to HN almost exactly two years from today: http://news.ycombinator.com/item?id=1014080
Poppycock. It doesn't get simpler than
a. newly bound variables are new
b. any variable which wasn't bound in the present scope must be bound in a enclosing scope.
If your language makes it much more complicated than First Order Logic (http://cnx.org/content/m12081/latest/), you're doing it wrong.Of course, it's kind of socially acceptable to get wrong because a lot of language designers didn't think it through and used the same operator for both binding and reassigning a variable (i.e. '=').
Pretend like you're a beginner, learning this stuff for the first time. If everywhere you see a variable "A", within a certain lexical scope, it means the same thing ... that's much simpler to understand than if "A" means three different things at three different places, because you happened to shadow it twice.
Either way, I think it is what it is and the benefits of CS very much outweigh the cons. Thanks for the feedback
I didn't want to change the default semantics, but I wanted to have a way for the programmer to be safe if they wanted to, so I created the `using` keyword for function declarations.
You explicitly declare what you intend to overwrite in the lexical scope, including overwriting nothing at all with `using nil`.
http://www.rubyist.net/~matz/slides/rc2003/mgp00010.html
Source: https://github.com/jashkenas/coffee-script/issues/712#issuec...
https://github.com/jashkenas/coffee-script/issues/712#issuec...
https://github.com/jashkenas/coffee-script/issues/712#issuec...
It's open source. Why not fork it and get some like minded coders to change it with you?
If you need global variables, it's sensible to just adopt a simple naming convention, like prepending g_ (or whatever pleases you) to all your variables. I already did that with plain JS and it's well worth the "effort".
Here is an example of what I'm talking about:
if isAir cx, cy, cz + 1 then addPlane('near', block)
Should be:
if isAir cx, cy, cz + 1 then addPlane 'near', block
Personally, I use them everywhere because I like having the stronger visual clue that this is a method I'm calling. I think making them optional in CS was a bad idea.
if isAir(cx, cy, cz + 1) then addPlane('near', block)
imho, so much more readable.
Once you understand the reach of CoffeeScript's top-level variables, it is easy to write bug-free code. Since you know that top-level variables have wide scope, you simply need to be judicious about putting variables at top-level scope. If a variable is not needed at top level scope, don't put it there.
Obviously, plenty of folks managed to write bug-free code in Python before "nonlocal" was invented. I'm not saying it's a bad idea, but you can avoid bugs without it.
((a = 5, b = 6, log = x -> console.log x) -> log a + b)()
I disagree. The simple solution to this is to write tests.
That's a step backwards. Code error checking should be done as early as possible. In order of earliness:
* Typing in the code. (Ideal: it is clear from the syntax that the code performs X instead of Y.)
* Compiling. (Strong type checking ensures you cannot return 5.3e7 or null from GetHostName.)
* Running the code at all. (Code contracts and assertions trigger if GetHostName returns "".)
* Automated unit tests. (Check that DB.GetHostName() returns the same string given to DB.Connect().)
* Automated integration tests. (Check that the DB module can connect to and retrieve useful data from a dummy database.)
* QA ("Hey Joe, the system hangs when I give "¤;\@" as my username and press the connect button rapidly for a few seconds.")
* Customer ("Hi the system has a problem, please fix.")
The further up, the faster, more accurately and with less "noise" the error can be discovered.
top_level_variable = null
f = ->
top_level_variable = "hello"
f()
console.log top_level_variable # prints hello 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. 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);
}
};Is there anyway to make the scope explicit in coffeescript?