Skip to content
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

CS2 Discussion: Features: let/const/var #4900

Closed
coffeescriptbot opened this issue Feb 19, 2018 · 87 comments
Closed

CS2 Discussion: Features: let/const/var #4900

coffeescriptbot opened this issue Feb 19, 2018 · 87 comments

Comments

@coffeescriptbot
Copy link
Collaborator

From @DomVinyard on July 11, 2016 12:13

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.

Copied from original issue: coffeescript6/discuss#1

@coffeescriptbot
Copy link
Collaborator Author

From @carlsmith on July 12, 2016 0:24

Whether we have let and var or not is a different question than whether we have const. The first two are related to scope, and const is about reassignment.

We should keep this discussion about let and var, and move const to a new issue.

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 nonlocal statements when you want to reassign names in outer scopes, the way CoffeeScript does by default, and we really want to avoid var and let and any other assignment keywords. They're especially awkward in a language where everything is an expression.

Bikeshedding

I think all assignments should be local, and we should have a variable available inside each function, just like arguments, called outer, that's a reference to the function's outer scope.

You would use outer the same way we use window in the browser to do global assignments:

outer.x = 1

If you had functions nested inside of each other, each lexical scope would have its own outer, so it would naturally be recursive. You could do outer.outer.outer... all the way to the global scope.

Assignments should have always been local, and it's natural to extend the idea behind window to all scopes. Then you don't need assignment keywords, can access any scope, and it works naturally as an expression.

@coffeescriptbot
Copy link
Collaborator Author

From @rattrayalex on July 12, 2016 4:55

const is now often the default in ES6 code. Making it convenient to use would be a plus. But not necessarily a priority.

My hunch is the outer proposal, while interesting, would be too far a departure to take on right away.

@coffeescriptbot
Copy link
Collaborator Author

From @rattrayalex on July 12, 2016 4:58

I don't think there's much reason to use let since coffeescript's var's have (most of) the same benefits; they are block-scoped.

If adding a const keyword isn't too hard, it might be worthwhile.

An alternative would be to have all variables by const by default, and allow explicit var or let declarations. I assume this would be more work, as the scoping code coffeescript undertakes would be mostly-removed.

@coffeescriptbot
Copy link
Collaborator Author

From @DomVinyard on July 12, 2016 8:24

You could do outer.outer.outer... all the way to the global scope.

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.

@coffeescriptbot
Copy link
Collaborator Author

From @carlsmith on July 15, 2016 16:11

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.

@coffeescriptbot
Copy link
Collaborator Author

From @JimPanic on July 19, 2016 9:17

I really want to see const in this new endeavour in one way or another. Maybe not in the first iteration, but definitely when targeting ES6. This is a key feature for me (and I guess a lot of other people as well) in ES6.

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 let the default, const easy to use and var the least common thing syntactically.

@coffeescriptbot
Copy link
Collaborator Author

From @carlsmith on July 19, 2016 13:20

Hi @JimPanic, welcome.

Regarding scoping, I'm in favour of leaving lexical scope as-is as well.

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 is clobbered by the inner assignment. Whereas, without an explicit nonlocal x statement, Python will never clobber names outside the local namespace.

    x = False

    def f():
        x = True
        print x       # True
    f()

    print x           # False

We can avoid clobbering x in CoffeeScript too, if we introduce the name into the local namespace as a parameter, but you still have to know that that name exists in some outer scope to preempt the 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 global declarator as we have window.x already.

If let makes a variable block-scoped and const makes the name un-reassignable and block-scoped, neither does what we need.

Even if we keep assignments nonlocal, if we introduce declarators, we would really need declarators for local, const and local const.

The benefit of having block-scope in CoffeeScript is slim. We can always create a new scope with do ->, and any variables in the function will be effectively block-scoped (again, assuming we don't clobber anything). Having let would allow us to do this:

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 let, and it was only introduced to fix different problems to the ones CoffeeScript has. We don't have much use for it.

I personally think outer.xis better than nonlocal x because it's explicit about which scope it references, and follows logically from window.x. Still, I'm happy to hear other ideas.

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

@coffeescriptbot
Copy link
Collaborator Author

From @JimPanic on July 19, 2016 13:58

@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.

@coffeescriptbot
Copy link
Collaborator Author

From @carlsmith on July 19, 2016 14:3

@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.

@coffeescriptbot
Copy link
Collaborator Author

From @rattrayalex on July 20, 2016 20:25

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.

@coffeescriptbot
Copy link
Collaborator Author

From @rattrayalex on July 20, 2016 20:27

[const] is a key feature for me

@JimPanic can you elaborate? I intuitively feel the same way – I enforce const-by-default in my eslint – but curious to hear if there are additional reasons why const is useful.

@coffeescriptbot
Copy link
Collaborator Author

From @rattrayalex on July 20, 2016 20:39

Any thoughts on const being used like so:

x := 7  # const x = 7

And all other = being treated as they are today, either using var or let?

@coffeescriptbot
Copy link
Collaborator Author

From @rattrayalex on July 20, 2016 20:43

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.

@DomVinyard re-reading this, I'm not sure I understand what you originally meant. Can you clarify?

@coffeescriptbot
Copy link
Collaborator Author

From @carlsmith on July 20, 2016 21:29

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 x :=? 7. If it was a short word, but still a normal operator, it wouldn't look as cryptic: x be 7 and x be? 7 looks more like regular CoffeeScript. I don't think it should be called be though. Just, if there was a good, short word, that would be better than having a :=? operator :)

@coffeescriptbot
Copy link
Collaborator Author

From @JimPanic on July 22, 2016 8:38

@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 const by default? Does your linter settings just yell at you when you do not declare something as const? :D

@coffeescriptbot
Copy link
Collaborator Author

From @JimPanic on July 22, 2016 8:39

@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 :=? ?

@coffeescriptbot
Copy link
Collaborator Author

From @carlsmith on July 22, 2016 12:55

@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 ?=, so if we have a constant assignment operator like :=, we'd need an existential constant assignment operator, which would end up looking like ?:=.

@coffeescriptbot
Copy link
Collaborator Author

From @carlsmith on July 22, 2016 13:26

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 is and isnt operators from CoffeeScript. CoffeeScript used to have an aint operator that compiled to !==, but it got dropped in favour of just having the current isnt alias, but that's confusing. People often shorten a is not b to a isnt b, expecting them to mean the same thing, like they do in English, but a is not b compiles to a == !b, while a isnt b compiles to a !== b.

If we just kept the current == and != CoffeeScript operators (which compile to === and !==), and got rid of isnt altogether, then is would be a good constant assignment operator.

    i = 0
    pi is 3.141

Then a ?is b would work as an existential assignment operator.

If we do a backwards incompatible CoffeeScript, we should definitely fix anything that is accepted as broken and easy to fix. Removing is and isnt would be trivial. We already have conventional, unproblematic == and != operators. And is would be a really nice constant assignment operator.

It's also worth mentioning that Python has an is operator. It's used to test whether two expressions evaluate to the exact same object in memory.

    a = b = []
    a is b         # True

    a, b = [], []
    a is b         # False

Using is for assigning constants would be a bit different, but still similar to Python - they both kind of mean is actually rather than equals.

@coffeescriptbot
Copy link
Collaborator Author

From @DomVinyard on July 22, 2016 14:25

@rattrayalex

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.

@coffeescriptbot
Copy link
Collaborator Author

From @DomVinyard on July 22, 2016 14:40

@carlsmith Firm -1 from me for redefining is.

@coffeescriptbot
Copy link
Collaborator Author

From @rattrayalex on July 22, 2016 16:24

How do you enforce const by default? Does your linter settings just yell at you when you do not declare something as const?

Yes – it's an ESLint setting to always use const unless you redefine the variable later.

we'd need an existential constant assignment operator, which would end up looking like ?:=.

I don't think an existential constant assignment operator makes sense 😉. ?= is used for reassignment, which isn't possible with const.

@coffeescriptbot
Copy link
Collaborator Author

coffeescriptbot commented Feb 19, 2018

From @rattrayalex on July 22, 2016 16:55

explicit constants should really be supported somehow.

I'm increasingly convinced of this as well personally. Should probably add to coffeescript6/discuss#8.

Avoiding having to add a new operator is worth fighting hard for in every case.. if CS is to retain its CSiness.

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.

@coffeescriptbot
Copy link
Collaborator Author

From @rattrayalex on July 22, 2016 16:59

Firm -1 from me for redefining is.

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 =s to is, and only once that is 100%-for-sure-done across your whole project, change most of your =s to is.

I also happen to think it'd be a bit less readable than something with symbols, given the ubiquity of the = for assignment across programming languages.

@coffeescriptbot
Copy link
Collaborator Author

From @rattrayalex on July 22, 2016 17:1

My understanding is the primary objection to := is the conditional assignment scenario, which as I outlined above probably doesn't apply. Are there others?

I think the leading alternative at this point would probably be to just pass const through, or come up with a similar (ideally shorter) word.

Thoughts?

@coffeescriptbot
Copy link
Collaborator Author

From @carlsmith on July 22, 2016 22:0

I don't think an existential constant assignment operator makes sense 😉. ?= is used for reassignment, which isn't possible with const.

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 :=, but still wish it was prettier.

square := (x) -> x * x

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?

@coffeescriptbot
Copy link
Collaborator Author

From @rattrayalex on July 23, 2016 2:11

but still wish it was prettier.

Agreed.

remember that we use assignment expressions in lots of places where they need to be concise.

Would you be willing to provide a few quick examples for illustrative purposes?

or can you just not define a parameter as a constant?

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.

CoffeeScript should make one big breaking change

Amen.

then treat TC39 as our standards process

I really need to learn more about TC39 😃

@coffeescriptbot
Copy link
Collaborator Author

From @carlsmith on July 23, 2016 2:57

Would you be willing to provide a few quick examples for illustrative purposes?

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.

@coffeescriptbot
Copy link
Collaborator Author

From @carlsmith on July 23, 2016 3:10

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.

@coffeescriptbot
Copy link
Collaborator Author

From @rattrayalex on July 23, 2016 3:13

Wow, I've never seen the employees code before. Looks awesome though.

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.

@coffeescriptbot
Copy link
Collaborator Author

From @dadleyy on July 27, 2016 6:19

ah. I feel like having it cluttered by := would be worrysome to though, no? Is the best case scenario here a compiler that detects re-assignment and appropriately decides let/const/var without explicit user involvement?

@coffeescriptbot
Copy link
Collaborator Author

From @JimPanic on July 27, 2016 6:32

Since the assignment with := only happens once, but usage of variables is probably more often, I wouldn't think so.

My problem with inference of let/const/var is that it completely goes against the advantage of const as an explicit marker. You'll never know whether a variable is declared as const unless you read the complete code of the current scope.

I do get your point with all-caps const variables and I've used that in Ruby a lot. But it kind of bugged me to write and read all-caps variable names as well.

What do other people think about this?

@coffeescriptbot
Copy link
Collaborator Author

From @JimPanic on July 27, 2016 6:35

It all boils down to taste, and I'm frank about it: I don't like all-caps words and I find := vs. = to look better and coincidently they correlate quite well with the mathematical use of those operators: https://en.wikipedia.org/wiki/List_of_mathematical_symbols#Symbols_based_on_equality .

So basically your proposal would work equally well but I personally don't like it as much. :)

@coffeescriptbot
Copy link
Collaborator Author

From @carlsmith on July 27, 2016 6:44

I'm totally against SQUARE = (x) -> x * x. It's a nightmare to have to hold Shift every time you type a name as well.

It also destroys all of our naming conventions, which span many languages.

@coffeescriptbot
Copy link
Collaborator Author

From @dadleyy on July 27, 2016 6:52

Yeah I didn't realize people were using const so much; having too many uppercased symbols would definitely get annoying (though one or two is definitely fine @carlsmith, I wouldn't consider that a nightmare). I'm just worried about departing from coffeescript too much by adding :=. If that's what people want and it makes it in, I'm still going to use this new language so my case is pretty moot.

@coffeescriptbot
Copy link
Collaborator Author

From @carlsmith on July 27, 2016 7:03

One or two is fine, but most names are constants.

@rattrayalex - In the example I posted, Employee should still be a constant.

Why can we not make properties constant? We can make properties of window constant. Every name is really just the property of some scope. I don't like the idea of adopting broken operators. If ES6 has a broken constant operator, then maybe we need to fix it.

@coffeescriptbot
Copy link
Collaborator Author

From @carlmathisen on July 27, 2016 8:46

@carlsmith: We can make properties of window constant.

Didn't know that - how?

@coffeescriptbot
Copy link
Collaborator Author

From @carlsmith on July 27, 2016 9:21

I just meant that global assignments are to properties of the window object, so outside lexical or modular scope, const x = 1 and const window.x = 1 are equivalent, but the second is apparently illegal.

I've tried to read up on this, as it's a bit confusing - you assume it's as simple as it seems - but the usual docs don't dive into any detail. Gonna search ESDiscuss later, and see what's been discussed already.

@coffeescriptbot
Copy link
Collaborator Author

From @carlmathisen on July 27, 2016 9:44

@carlsmith: const x = 1 and const window.x = 1 are equivalent

I don't think that is the case, because var x = 1 is scoped, and x = 1 (without var, let or const) is assigned to window.

const x = 1;
alert(window.hello);

outputs undefined, while

x = 1;
alert(window.hello);

outputs 1

@coffeescriptbot
Copy link
Collaborator Author

From @carlsmith on July 27, 2016 12:13

Thanks @carlmathisen. Yep, you're right. I never knew it worked like that. It just never came up. That makes things consistent at least. And the ability to make properties read-only makes constproperties redundant, which wraps the whole thing up. Thanks again for putting me straight. I at least understand the decisions now.

ES6 gave JavaScript features we really needed, but also made a pretty messy language even messier :(

We ultimately need a new language, with JS bindings, but with its own semantics that refine JavaScript, removing cruft like the special arguments array type and 'temporal dead zones', and fixing coercion and exception handling etc. etc. Once WASM matures, it'll be much easier to do without the performance penalty of using an interpreter VM written in JavaScript instead of just compiling to JS.

@coffeescriptbot
Copy link
Collaborator Author

From @DomVinyard on July 28, 2016 1:11

We ultimately need a new language, with JS bindings, but with its own semantics that refine JavaScript

I'm here because I need Coffeescript. And because it would be nice to get a community together again to lovingly support it going forward.

It's still my belief that there is no need for a var/let/const distinction in Coffeescript and that 'a variable is a variable' is enormously powerful.

@coffeescriptbot
Copy link
Collaborator Author

From @JimPanic on July 28, 2016 4:09

ES6 gave JavaScript features we really needed, but also made a pretty messy language even messier :(

That's certainly true. I hope a few of those messy bits will get cleaned up over time in the next years, though. Given the pace ES is moving at right now, this is not too unlikely.

It's still my belief that there is no need for a var/let/const distinction in Coffeescript and that 'a variable is a variable' is enormously powerful.

I think it's a good feature to have as long as you don't have to use it. I do want to be able to use const if I deem necessary, though, and not have CS stand in the way.

@coffeescriptbot
Copy link
Collaborator Author

From @carlmathisen on July 28, 2016 4:26

But is it a core focus feature, right now? It's absence is certainly not in the way of ES6 compatability, such as classes.

IMO it's nice to have at best, not need to have.

@coffeescriptbot
Copy link
Collaborator Author

coffeescriptbot commented Feb 19, 2018

From @JimPanic on July 28, 2016 4:32

const is quite a low-hanging fruit, I think (but am not sure). Personally, for me it is a need a to have, as opposed to classes which I don't use at all. So this is a matter of personal priorities and eventually the priorities we agree upon in the project. It does not seem to be a technical decision after all. :)

It is not listed as the proposed core focus features, but as one of points in the "four core may be too short"-list. Can you maybe head over to the coffeescript6/discuss#8 issue and comment there as well regarding priorities?

@coffeescriptbot
Copy link
Collaborator Author

From @DomVinyard on July 28, 2016 8:03

Personally, for me it is a need a to have

I can fathom the sort of project where the overhead of const over var is a performance bottleneck remedy. I can't fathom why anybody would pick coffeescript for that project.

@coffeescriptbot
Copy link
Collaborator Author

From @carlsmith on July 28, 2016 8:45

We ultimately need a new language, with JS bindings, but with its own semantics that refine JavaScript

I'm here because I need Coffeescript. And because it would be nice to get a community together again to lovingly support it going forward.

I was making an observation about what the world ultimately needs. I don't see how your motivations for being here counter that.

Personally, for me it is a need a to have, as opposed to classes which I don't use at all.

The ability to extend ES6 classes is required to use the APIs provided by modern JavaScript libraries. If you don't have that feature, you can't use a growing list of libraries. We don't need constants for ES6 interop. It's not about personal preferences. We need ES6 classes to avoid becoming obsolete, but constants are entirely optional.

@coffeescriptbot
Copy link
Collaborator Author

From @rattrayalex on July 28, 2016 10:21

const is a nice-to-have in my book as well, but @JimPanic is certainly not alone in wanting it.

Let's talk priorities on the priorities thread, and avoid shooting down ideas just because they're not "absolute must-haves"

@coffeescriptbot
Copy link
Collaborator Author

From @carlmathisen on July 28, 2016 9:29

You're right @rattrayalex, sorry about the tangent.

@coffeescriptbot
Copy link
Collaborator Author

coffeescriptbot commented Feb 19, 2018

From @GeoffreyBooth on Sep 6, 2016 12:03

Carrying over a discussion from coffeescript6/discuss#30, is interoperability affected if we don’t add support for const? Like will there be any library we can’t use if we can’t send a const-defined variable into it, for example? Or perhaps a build tool that optimizes based on const vs var or let?

One sort-of case I can think of is mentioned in this comment on the modules PR. Basically, anything you import is essentially a const. In this:

import foo from 'lib'

foo is read-only, meaning it’s essentially a const; if you try foo = 2 later on, an error will be thrown. I wonder if it’s weird to have these implicit constants defined via import, while no other constants can be created in any other way. @greghuc, with regards to your ”mental model” of needing to keep track of which variables are read-only and which aren’t, unfortunately with module support you have no choice but to fight that battle (assuming you want to use modules).

@coffeescriptbot
Copy link
Collaborator Author

From @zeekay on Sep 6, 2016 17:23

Any thoughts on const being used like so:
x := 7 # const x = 7

I'm not a fan as := for const declaration as it's used in Go (and other languages) for variable declaration. If we were going to break nonlocal assignment in CoffeeScript I'd prefer to use := for new variables and = for assigning to an existing variable (as in Go). This makes assigning to a variable in an outer scope very clear and tends to actually prevent bugs whereas I've never found const to provide much value.

As const does seem to be fairly popular though, support makes sense. I'd argue that we should just we make const pass through like other ES6 constructs.

const x = 7

This is perfectly acceptable and matches JavaScript which is preferable to new syntax.
It's readable and fine, in my opinion.

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 let or explicit :=/=.

@coffeescriptbot
Copy link
Collaborator Author

From @GeoffreyBooth on Sep 6, 2016 17:57

zeekay I think := was selected because const can only be assigned as part of its declaration, so it was appropriate. There is a strong convention in CoffeeScript to not use keywords for declaration (hence no var, no function, etc.; exceptions exist like class, but I don’t think people want to add any more). We can’t break backwards compatibility, so changing the behavior of = is not an option.

By nonlocal assignment, I assume you mean CoffeeScript’s habit of creating a var line at the top of whatever scope you’re in and declaring all variables there, then assigning them wherever you reference the variable? That won’t be possible with const: by definition, it needs to be assigned when it’s declared. I assume that support for const would put its declaration/assignment at the same place in the code that you typed it in CoffeeScript, rather than moving it up to the top of the scope.

@coffeescriptbot
Copy link
Collaborator Author

From @zeekay on Sep 6, 2016 18:48

By nonlocal assignment I was referring to how it's not possible to shadow an outer variable:

x = 1
do ->
    x = 2 # x assigns to nonlocal x above
x # == 2

Which is the terminology used above in this discussion (as a nod to Python's nonlocal statement, I believe). The default of nonlocal assignment is very confusing to newcomers and does lead to bugs, in my experience.

I would argue that the lack of keywords for declaration was due to lack of necessity (when CoffeeScript was introduced there was only var to be concerned with). CoffeeScript has actually introduced a great number of keywords (loop, do, is, isnt, etc). I tend to find keywords easier to read and reason about compared to new syntactic structures and that's been one of the things I've come to appreciate about CoffeeScript.

@coffeescriptbot
Copy link
Collaborator Author

From @zeekay on Sep 6, 2016 18:58

As a quick follow-on: I'd be fine with changing declaration behavior. Compiling normal declarations directly to let would lead to an improvement in the readability of the compiled JavaScript and more closely match what modern JavaScript developers would write by hand.

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 := as a way to force declaration, which would not break backwards compatibility:

x = 1
do ->
    x := 2 # declares a new x
x # == 1

Which would be a better use of := than as shorthand for const.

@coffeescriptbot
Copy link
Collaborator Author

From @GeoffreyBooth on Sep 6, 2016 23:52

@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 const assignment (the proposed := operator) and automatic usage of let when appropriate. These are really two separate feature requests, especially considering that the former can be implemented today without a flag (since it’s opt-in by using the new syntax) while the latter can’t (since it’s automatic). I created coffeescript6/discuss#31 to cover the proposed new operator. Automatic lets are much farther in our future, when we’re onto the task of converting all of CoffeeScript’s output to be as ES-latest as possible, so I’m not going to bother creating an issue for it (yet). But feel free if you want to discuss it further.

@coffeescriptbot
Copy link
Collaborator Author

From @mrmowgli on Sep 7, 2016 16:46

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.

@coffeescriptbot
Copy link
Collaborator Author

From @rattrayalex on Sep 7, 2016 21:33

@GeoffreyBooth not sure if anyone answered your question:

is interoperability affected if we don’t add support for const?

I don't believe so, no. const is a feature people like, but not an interoperability concern.

@coffeescriptbot
Copy link
Collaborator Author

From @carlsmith on Sep 8, 2016 13:54

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.

@coffeescriptbot
Copy link
Collaborator Author

coffeescriptbot commented Feb 19, 2018

From @rattrayalex on Sep 9, 2016 9:10

My understanding of our consensus:

  1. We'll probably just keep compiling to var for the time being, as their is no practical benefit of using let or const in the output.
  2. const may be implemented with := or something similar, but won't be inferred; discussion for that has moved to CS2 Discussion: Features: const assignment operator coffeescript6/discuss#31.
  3. At some point in the future, coffeescript may compile to let/const instead of var, but it's not a priority and not worth discussing now.
  4. The decaffeinate project can be used if you want ES6 output today.

As such, I am closing this issue for now. If I get sufficient 👎 reactions to this comment, we'll re-open.

@coffeescriptbot
Copy link
Collaborator Author

coffeescriptbot commented Feb 19, 2018

From @GeoffreyBooth on Sep 9, 2016 9:22

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/const is its block-scoping, i.e.:

let a = 1;
if (true) {
  let b = 2;
}
console.log(b); // undefined

This is a dramatic improvement over var, and a big reason why let and const have become popular features. We need to at least discuss if this is something CoffeeScript should have, separate from the feature of const that means “throw an error on reassignment.”

I think we could have both, via := and perhaps :== operators (or whatever two operators people think are best):

  • a := 1 would mean, “declare and assign a with the value of 1, using let if a gets reassigned in this block and const if it never gets reassigned.”
  • a :== 1 would mean, “declare and assign a with the value of 1 using const. If it gets reassigned later, throw an error.”

We don’t necessarily need the second operator, if we don’t care to give people a way to force const. I’m not sure how popular the “throw an error on reassignment” feature is, but I suspect it’s quite popular.

Agreed that we should close this issue though, in favor of coffeescript6/discuss#31 and whatever new issue is created to discuss this “lexical assignment operator”.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants