-
Notifications
You must be signed in to change notification settings - Fork 4
CS2 Discussion: Features: let/const/var #1
Comments
Whether we have We should keep this discussion about Should we even keep CoffeeScript's nonlocal assignment rule? If were making breaking changes, we should consider changing that as it was quite controversial - all assignments are currently nonlocal. The name lookup starts locally, and works outwards until it finds the name and reassigns it. If it doesn't find the name, the assignment is local. In Python, all assignments are just local, which is what you normally want to happen. Lexical scope exists to keep variables locally defined. You never have to worry about clobbering something in the global scope with a local variable like you do in JS and CoffeeScript. The problem with Python is that it uses BikesheddingI think all assignments should be local, and we should have a variable available inside each function, just like You would use
If you had functions nested inside of each other, each lexical scope would have its own Assignments should have always been local, and it's natural to extend the idea behind |
My hunch is the |
I don't think there's much reason to use If adding a An alternative would be to have all variables by |
That sounds like an absolute nightmare. Hard-coding your depth in the scope. It will be very easy to reimagine all of coffeescript's features under the mandate of 'allowing breaking changes' - but I think there is a good case for picking a few bits of low hanging fruit and then addressing the rest once we're up and running. let/var/const would be a good candidate for leaving alone, i think. |
I don't see a problem with absolute scope references, when scope is already lexical. Still, we have more worthwhile stuff to discuss, so yeah, forget it. |
I really want to see Regarding scoping, I'm in favour of leaving lexical scope as-is as well. In the future it might be a good idea to make |
Hi @JimPanic, welcome.
You misunderstood the problem I was trying to address. CoffeeScript will always have lexical scope as-is. No one wants to change that. It's the way CoffeeScript mandates that all assignments are nonlocal that's the issue. It's always been a pretty controversial feature, and one of the most popular criticisms of CoffeeScript. For an example of the feature, here's two seemingly similar blocks of code, the first is CoffeeScript, the second is Python. They do different things though: x = false
do ->
x = true
console.log x # true
console.log x # true In CoffeeScript, the outer x = False
def f():
x = True
print x # True
f()
print x # False We can avoid clobbering x = false
do (x) ->
x = true
console.log x # true
console.log x # false Lacking any real evidence, I can just say from experience with Python that nonlocal assignment is pretty rare. You almost always want assignments to be local. I assume @jashkenas only went with nonlocal assignment to avoid having to have declarators. There's no other sane reason to do it. If we're going to change the language design to introduce declarators, then we should definitely make assignment local by default and have a declarator for nonlocal assignment. We don't need Python's If Even if we keep assignments nonlocal, if we introduce declarators, we would really need declarators for The benefit of having block-scope in CoffeeScript is slim. We can always create a new scope with if foo
let x = true
let y = false But, we can already do this anyway: if foo then do ->
x = true
y = false JavaScript became considerably more complicated by introducing I personally think Taking declarators from JavaScript requires changing them to fit CoffeeScript's nonlocal assignment feature, which may in turn require any declarators to be renamed for their new semantics, so we'd basically need to define our own declarators from scratch. And we really should try and do everything we can to avoid introducing declarators, given that they have been rejected from CoffeeScript for seven years, and they make everything look like Java. jQuery ->
local const square = (x) -> x * x |
@carlsmith You are right, I did misunderstand. I always thought CS was favouring the innermost scope in assignments. Lucky me it didn't bite me so far. |
@JimPanic :) It's not obvious what CoffeeScript is doing, especially when it seems to be doing what you'd expect, coming from other languages. It doesn't bite that often, but when it does, it can be totally baffling. |
Thanks very much @carlsmith for the terrific explanation there. Didn't understand that bit myself so well till now 😄 I do agree that it would likely be too ambitious to change how scoping works, unless we can simplify the coffeescript compiler by staying closer to JS's behavior. |
@JimPanic can you elaborate? I intuitively feel the same way – I enforce |
Any thoughts on x := 7 # const x = 7 And all other |
@DomVinyard re-reading this, I'm not sure I understand what you originally meant. Can you clarify? |
Adding a constant operator is easier than adding declarators. It changes the language less. The operator is ok, but will get a bit messy when its |
@rattrayalex It helps avoiding so many bugs and enables a more declarative way of coding, which in turn helps keep code readable and (more) testable. How do you enforce |
@carlsmith I was thinking the same; a different assignment operator would go well with the CS syntax as it is now, since there are no declarator keywords. Why the question mark in |
@JimPanic - My bad: I got it back-to-front (I rarely use the feature this way), but you have an existential assignment operator in CoffeeScript that looks like |
We could figure out from static analysis whether a name is assigned more than once, and make names that are never reassigned constants automatically, but expect JavaScript engines already do this, so any efficiency gains would likely be negligible. More importantly, people want explicit constant assignment/declarations to communicate that constraint to other programmers. Given that it's a popular CoffeeScript feature request, and already part of ES6, explicit constants should really be supported somehow. There's an argument for getting rid of the If we just kept the current i = 0
pi is 3.141 Then If we do a backwards incompatible CoffeeScript, we should definitely fix anything that is accepted as broken and easy to fix. Removing It's also worth mentioning that Python has an a = b = []
a is b # True
a, b = [], []
a is b # False Using |
Coffeescript succeeded, at least partially, because it traded out efficiency optimisations for simplicity in a bunch of contentious but elegant ways. Not distinguishing between let and const fits that core simplicity brief. Perhaps this means that a few edge-projects will have to use vanillaJS for certain classes of application because the overhead of trading out lets for consts would trip the project from acceptable into unacceptable but I think that is a reasonable cost to keep things simple. Avoiding having to add a new operator is worth fighting hard for in every case.. if CS is to retain its CSiness. |
@carlsmith Firm -1 from me for redefining is. |
Yes – it's an ESLint setting to always use const unless you redefine the variable later.
I don't think an existential constant assignment operator makes sense 😉. |
I'm increasingly convinced of this as well personally. Should probably add to #8 .
I disagree with this sentiment, actually. While maintaining a decent degree of backwards-compatibility would be nice, I don't think we should shy away from adding new features, especially those that are part of ES6. The number one purpose of this org is to ensure that CoffeeScript isn't behind ES6 at all – that anything* you can do conveniently in JavaScript, you can do at least as conveniently in CoffeeScript. Furthermore, language innovation is a core aspect of the "CSiness" of CoffeeScript IMO. Jeremy combined the most convenient language features he could find from other languages, made it easy to write good javascript, and added some new ideas into the mix as well. We should certainly think really hard about whether any new features are worth doing – and focus on compatibility with ES6 first – but I also don't think it's something we should shy away from. * Anything that you should be doing, anyway. Making "the bad parts" and generally poor programming practices less convenient, or even impossible, is a good thing. |
I personally agree. However, to keep a healthy environment where people feel comfortable voicing new ideas they might not be 100% comfortable with yet, let's try to back up -1's with a few calm reasons. In this case, my reason is primarily difficult of porting – redefining a language keyword to something completely different could make updating quite difficult, as you'd have to both translate all existing I also happen to think it'd be a bit less readable than something with symbols, given the ubiquity of the |
My understanding is the primary objection to I think the leading alternative at this point would probably be to just pass Thoughts? |
I didn't think about that. Sorry about the noise then. I mentioned not using that feature much when I misspelled the operator I'm with @rattrayalex on adding new features, but feel pretty strongly that we should stick to things that are just sugar for well established idioms or that have already been standardised by ECMA. CoffeeScript should make one big breaking change, then treat TC39 as our standards process. Now that CoffeeScript has inspired JavaScript to evolve, we can co-evolve with JavaScript in a way Jeremy couldn't in 2009. So, yeah - sorry to ramble - assuming there will be no need to have an existential constant assignment operator, then I would personally be ok with
I still feel strongly that we should avoid declarators if at all possible. It changes the language, and we use assignment expressions in lots of places where they need to be concise, not just in standalone statements.. Also, do we need a story for constant function parameters, or can you just not define a parameter as a constant? |
Agreed.
Would you be willing to provide a few quick examples for illustrative purposes?
Well, you can't in es6, so we'd really be going above and beyond if we implemented it in cs6. It's not an unappealing feature imo but probably not something to worry about yet.
Amen.
I really need to learn more about TC39 😃 |
I meant using assignment expressions like this: if (stuff = getStuffOrReturnNull) then use stuff
employees = [
ali = new Employee "Ali"
bob = new Employee "Bob"
]
Because assignments are expressions, you can write one anywhere you can write an expression. It can be helpful when you want to make assignments conditionally, and lets us use some shorthand expressions for initialising variables. |
On the TC39 comment: I really just meant that we should follow the ECMAScript standards when introducing features that go beyond sugar for common JS idioms. We have the luxury these days of a standards process that moves quickly, releases often and develop editions in parallel. It has some of the best minds in our community, and all the vendors are on board. You can get involved through ESDiscuss, and influence the spec, but for the most part, we don't need to. It works. If Jeremy had followed the spec, we wouldn't have the problem we now have with incompatible classes. Obviously, in 2009, following the spec would have made CoffeeScript suck. |
Wow, I've never seen the https://github.com/michaelficarra/CoffeeScriptRedux/wiki/Intentional-Deviations-From-jashkenas-coffee-script#intentional-deviations might be relevant here once we get into the weeds, especially if we decide to build on CSR. Thanks for sharing the examples! Helpful. |
You're right @rattrayalex, sorry about the tangent. |
Carrying over a discussion from #30, is interoperability affected if we don’t add support for One sort-of case I can think of is mentioned in this comment on the modules PR. Basically, anything you import is essentially a import foo from 'lib'
|
I'm not a fan as As
This is perfectly acceptable and matches JavaScript which is preferable to new syntax. Coming from Python, CoffeeScript's nonlocal assignment was kind of confusing, at least initially. I no longer find it very difficult to reason about, but I cannot think of a single person I've met who is a fan of it (and of course it's been written about for quite some time, never positively). Personally, I would not mind ditching it in favor of implicit |
@zeekay I think By nonlocal assignment, I assume you mean CoffeeScript’s habit of creating a |
By nonlocal assignment I was referring to how it's not possible to shadow an outer variable:
Which is the terminology used above in this discussion (as a nod to Python's I would argue that the lack of keywords for declaration was due to lack of necessity (when CoffeeScript was introduced there was only |
As a quick follow-on: I'd be fine with changing declaration behavior. Compiling normal declarations directly to The more interesting bit of the discussion in my mind is what to do (if anything) about CoffeeScript's (for lack of better terminology) nonlocal assignment. It might be nice to introduce
Which would be a better use of |
@zeekay may I invite you to open an issue suggesting changing nonlocal assignment? And the community can debate its merits there. This thread covers both explicit |
I can see why the const becomes important, especially when dealing with code security. Let being the counterpart to avoid intentional abuse of the browser environment. I don't think anything would directly break, but I do think there is a good reason to include the functionality. Perhaps there are some intelligent rules to creating let assignments automatically. +1 for := assuming let and keeping the const keyword. |
@GeoffreyBooth not sure if anyone answered your question:
I don't believe so, no. |
I can't see any way it could undermine interoperability either. It's the reference that is constant, not the value, and a library wouldn't even see the name, unless you were sharing globals. Every interface is focussed on the values, never the way they're expressed. |
My understanding of our consensus:
As such, I am closing this issue for now. If I get sufficient 👎 reactions to this comment, we'll re-open. |
If I could amend that consensus a little, @zeekay described an alternate proposal on Gitter that he’s planning to present as a new issue soon, probably this weekend. Basically his point is that the great advantage of let a = 1;
if (true) {
let b = 2;
}
console.log(b); // undefined This is a dramatic improvement over I think we could have both, via
We don’t necessarily need the second operator, if we don’t care to give people a way to force Agreed that we should close this issue though, in favor of #31 and whatever new issue is created to discuss this “lexical assignment operator”. |
I found [this discussion][1] talking about `let` and `const` to be helpful to understand the decisions why these keywords were not added to CoffeeScript v2. In particular, I think we can improve the documentation by linking to these examples on the section about why they're unsupported. Basically, it comes down to using `do ->` to approximate `let` and `const`. I'm down to re-word anything here, and I also completely understand if this is not something you want in the documentation. [1]: coffeescript6/discuss#1
Migrated to jashkenas/coffeescript#4900 |
Personally, I believe these should be untouched. I can see that there is a case for implementing const in almost any language remit. But not coffeescript.
The text was updated successfully, but these errors were encountered: