4 ms·
Both JavaScript and CoffeeScript got it wrong. Here's the right solution: 1) Keep the distinction between declaration and assignment. 'var x = 1' introduces a
by cousin_it 13y ago
Both JavaScript and CoffeeScript got it wrong. Here's the right solution:
1) Keep the distinction between declaration and assignment. 'var x = 1' introduces a new variable, 'x = 1' changes an existing variable.
2) Remove globals from the language. 'x = 1' becomes an error unless there's a 'var x' in scope.
3) Change 'var' declarations so they apply to the containing {} block, not the whole containing function.
There's wouldn't be much to discuss here, if not for historical accidents. Brendan should've known better because he knew Scheme, which had it exactly right, and Jeremy should've known better because he saw the mistakes of JavaScript, but they both screwed up.
If you're an aspiring language designer, please learn from this. There are valid disagreements in language design, but this isn't one of them. (Some other solved problems: modules > header files, option types > nulls, covariant arrays don't work, etc.)
- masklinn 13y ago1. and 2. are solved in javascript by using strict mode (now in a browser near you) 3. is solved in ES6 with `let` (currently working in Firefox, behind a flag in Chrome, no support in Opera, Safari, MSIE or Node). Note that let also 1. isn't hoisted and 2. forbids double declaration (`let x; let x;` is an error)
- cousin_it 13y agoThanks! That's very nice, among possible backward compatible solutions I cannot imagine a better one. Now I wonder what kind of fix the CoffeeScript folks will make, when they admit the problem...
- masklinn 13y agoI don't think they can fix that one in CS short of changing the semantics of the language: they decided to infer scope (an error as far as I'm concerned) and because they wanted to avoid shadowing they went with generalizing scope inference (as opposed to Python, which always infers function-local scope unless specifically told otherwise, scope inference is still bad but slightly less so as it won't suddenly turn a local variable into a global one without warning due to a non-local change). I believe CS tried to copy Ruby as block scope inference works the same way, but Ruby uses its method/block duality to mitigate the issue: scope inference is generalizing across the (lexical) blocks of a method, but the inference stops at the method, if you assign to a name at the top-level (global) and assign to a name in a method you will create two different bindings. Coffescript has no such duality, and as a result can't use it for a "watertight seal" around scoping.
- cousin_it 13y agoGreat examples, I agree that conflating declaration and assignment seems to be a mistake that different languages try to mitigate in different ways. Another example is in http://www.paulgraham.com/arclessons.html http://www.paulgraham.com/arclessons.html, "Implicit local variables conflict with macros."
- Skalman 13y agoNew JavaScript features do just that: 2) Globals with 'x = 1' throws an error when run in strict mode. 3) They couldn't change the meaning of 'var', but they introduced 'let' which does just that - applies to a block rather than the whole function.
- happy_dino 13y agoThanks. I think this is the best comment in this discussion. If you hadn't written it, I would have sat down and done it.