-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CS3 Discussion: Assignment scope #4985
Comments
There was some side discussion of this in #4847 (comment), but this issue could perhaps serve as a better canonical place to track it. Here’s how I remember the consensus so far:
|
What about preserving the existing behaviour, while also allowing you to explicitly define a variable at the block level without hoisting it to the top (i.e. enable the use of var/let/const keywords and have it output directly as written)? |
@aminland See the quote from above:
Any solution that preserves the existing behavior while also allowing some other way to declare a variable means you now have two ways to declare variables. The consensus from the earlier issues was that preserving the simplicity of there being only one way to declare variables is our top priority. So really the choice is only between “do nothing” and “change the current output to be block scope instead of function scope.” |
If those are the only options then let's please not break backwards compatibility... Block scoping wouldn't actually enable you to do anything you can't currently accomplish with function scoping... |
Backwards compatibility is probably the top priority, since we don't want to fracture an already dwindling community. Also, block scoping shouldn't be written off as too complex. The Javascript community seems to be thriving with the addition of block scoping. There is clear demand for such a feature in Coffeescript. I would argue the greater risk is not matching Javascript on that flexibility. With that said, I think the best direction is probably adding the |
i think block scoping is most correct and i would definitely never thoughtlessly define a variable within a for loop (for example), instead defining its initial value outside the loop if that's the intent. but while i know i would be able to migrate my code if all variable declarations became so, unless there is a convenient way to use optional flags for such feature ( |
For the record, if block scoping were to be added to CoffeeScript in addition to the function scoping we already have, it would be via a new operator like |
For the record, it is clear from reading said comments that this is your opinion on the matter, and far from a universally-accepted truth. While I did not actually mean |
You are correct, |
Furthermore, it seems a new consensus has been established in regard to "block scoping by default" being too drastic of a breaking change, which has a strong possibility of fracturing the community. I think the argument between # Assign `y` with block scoping, then add its value to `x`
x + y := 1
# Looks like a syntax error
x + let y = 1 But I'm warming up to the idea of a package-specific flag to enable block scoping by default. Of course, you could argue this is toxic for open-source projects, since it would not be obvious whether the flag is being used without checking the configuration. But that should be their choice, instead of the language gate-keeping a useful feature. |
I wish CS could change to block-scoping without causing further abandonment. I wish someone could make a sophisticated tool to help migrate code for this change. Or, I wish there were an elegant way to opt-in to new features per file/module. Unfortunately, adding a keyword or operator is simply so much easier than all of the above that it remains tempting. Of course, "leave it like it is" may be good enough for people like me who simply prefer CS, not because of one particular feature or another. Some (admittedly distasteful) ideas:
|
I agree, it’s an annoying problem. It’s problematic to increase complexity when one of our prime selling points is simplicity. We could mimic ES5’s 'use block scope'
if yes
x = 'block scoped!' This is probably better than an extra compiler flag, for the reasons mentioned above (not knowing whether a file is written to be block or function scoped without looking elsewhere in the project, etc.). But is it really better than |
I'm a pretty big fan of block scoping as a default and think it would be a lot more intuitive for new users. I'd happily update all of my projects to properly support it assuming block scope became a default. I think mirroring modern JS here would have a lot of advantages long-term and be worth the intermediate pain. I suspect most of my projects would require little if any effort to support a switch to block scope. An automatic upgrade tool could presumably hoist all variables to the top of function scope, no? |
I agree with @zeekay. Block scoping by default is the way forward, and the upgrade path looks smooth. The JS community is evidence that the majority prefer block scoping. Anyone who disagrees can keep using CoffeeScript 2. |
Meh... In CoffeeScript, expressing a function is very quick and easy, so there is no need for the language to infer tighter scopes to keep things local. On the few occasions where block scope would improve anything, we can just wrap that code in its own lexical scope with a few extra characters. Lexical scope, based around functions (with associated concepts, like closure) is a beautiful idea that integrates concepts in a really elegant way. It all works so well in CoffeeScript that I personally think things are correct as they are. |
I wote for And I hope, that this error at least will be fixed: #4723 I use it just for clean syntax, also often use JS to avoid problems. |
that's not a bug, that's expected behaviour |
My two cents after a year of straight ES coding: I found that because of linters like eslint I had to go back through and hand tune all the vars to let and const from cs.
If we had linting working well in CS, I could convince people to allow CS checkins. As it stands now though, I am stuck.
I personally think we should never worry about such things in CS and generate let and const appropriately. I see mistakes in ES all the time with the use of let and const, but var is all kinds of taboo at the moment.
|
I did make an experimental branch that simply always output If it’s possible to reliably track variable references and assignments, which I think it might be, then we could output
If we know a variable isn’t being referenced, I wonder if we need the declaration line ( But the fact that our |
Late chime in but I do miss const. I would love to adopt CoffeeScript if it offered const as a storage modifier. Enums schemas regexes and identifiers are always const for me & have been since const was made available I also agree with switching |
I'd like to point out that there is, in fact, already two ways to declare variables in CoffeeScript, so it's just a question of whether it's worth making it simpler. Specifically, you can introduce new block variables with do ({ foo, bar } = {}) ->
# ... Are we the only ones doing this? 😀 Granted, technically, this is just function scope, but the point is that, in cases where you want to be sure of the scope, you can already do that. The choice already exists: the question is whether a block-assignment operator would be simpler and more elegant. Which I would think is self-evidently the case. 😊 |
I think this is worth exploration. As far as I'm aware, // current
((a) => {/* ... */})(a);
// could be
{let a = a; /* ... */} Fat arrow is probably what you want in most cases and as far as I can recall losing |
@Inve1951 Neat point about changing the output of Back to whether to make something more convenient than for item in loop
do (item) ->
callbacks.push -> ... item ...
#or
callbacks.push do (item) -> -> ... item ... I'd much rather write something like for let item in loop
callbacks.push -> ... item ...
#or
for const item in loop
callbacks.push -> ... item ... I can't think of how to write this with As none of this breaks backward compatibility, I think it could be added to CS 2. |
@edemaine I share the pain with loops and callbacks. Example: for item in items
console.log item New output: for (let item, i = 0, len = items.length; i < len; i++) {
item = items[i];
console.log(item);
} Example 2: item = null
for item in items
console.log item New output: var item;
item = null;
for (let i = 0, len = items.length; i < len; i++) {
item = items[i];
console.log(item);
} This also leaves a clear upgrade path for code relying on the current behavior - Simply declare Aside from this use case (loops) I'm still not convinced we need or even want block-scoped variables (except for aesthetics). There's one pain with |
I have introduced a non-breaking change which makes CoffeeScript aware of block scope: #5475. I believe this is a necessary prerequisite for this feature request. Please take a look if interested! |
I have also introduced something related but different: a distinct declaration, which is currently just using |
I know assignment scope has been discussed at length for CS2 (#4951), but I don't see a discussion in the context of CS3. So here it is.
Block scope
=
I'm strongly in favor of changing
=
fromvar
tolet
and using nearest block scope instead of function scope, as was proposed by @jashkenas here: coffeescript6/discuss#58 (comment)Shadowing avoidance
There was also talk of adding a
:=
operator for explicit avoidance of shadowing.Another option is the
let
keyword (which invites inclusion ofconst
).Just today, I thought of
:foo = 1
as another option.Concerns
@jashkenas said in coffeescript6/discuss#58 (comment):
..which rules out the
:=
operator, but maybe notlet
or:foo =
?If
=
is changed to block scope, the shadowing problem can be fixed without having two mental models of variable scope.In the same comment, @jashkenas said:
..but I assume this discussion is still "up in the air" for CS3.
Let me know if I missed any other ideas or concerns.
The text was updated successfully, but these errors were encountered: