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] Docs: Need to add breaking changes info about => differences in CS2 #4593

Closed
boris-petrov opened this issue Jun 29, 2017 · 15 comments
Closed
Labels
Milestone

Comments

@boris-petrov
Copy link

foo = bar =>
  console.log arguments

Is compile to:

foo = bar(() => {
  return console.log(arguments);
});

But according to this, arrow functions do not have their own arguments. I think this is a bug in CoffeeScript 2. Whenever arguments are used, that function should not compile to an arrow function. Or do you have some... um... arguments against that? :)

@vendethiel
Copy link
Collaborator

That's correct:

> (function f(x) { return (() => arguments)() })(1)[0]
1

@boris-petrov
Copy link
Author

@vendethiel - I understand what happens. I'm saying that this is not consistent with what one would expect from CoffeeScript. There are only anonymous functions in CoffeeScript which means that I can never get the real arguments of a function which is passed as an argument. I think this will break tons and tons of code. As it did mine.

Again, I'm saying that CoffeeScript should compile lamba functions that use arguments inside the old way - by capturing this and then using function() .... Do I make more sense?

@connec
Copy link
Collaborator

connec commented Jun 29, 2017

We've adopted ES2015 semantics for fat arrow functions to reduce the barrier for users working in both languages.

The best way to achieve this now would be to use a splat:

(args...) => console.log args

@connec
Copy link
Collaborator

connec commented Jun 29, 2017

This probably needs to be documented as a breaking change if it's not already. Edit: looks like it's not.

@boris-petrov
Copy link
Author

I don't think it is, I checked the documentation. I could have missed it though. But this is kind of bad... another example:

originalWindowError = window.onerror
window.onerror = (messageOrEvent, source, lineNumber, columnNumber, error) => # general window errors
  @_notify(error)
  originalWindowError?(arguments...)

How can I achieve the same effect with CoffeeScript 2?

@vendethiel
Copy link
Collaborator

Again, I'm saying that CoffeeScript should compile lamba functions that use arguments inside the old way - by capturing this and then using function() .... Do I make more sense?

Yes, thank you. I agree it's weird that -> and => have different arguments semantics.

@vendethiel vendethiel reopened this Jun 29, 2017
@vendethiel
Copy link
Collaborator

If anything, it doesn't seem to be documented on /v2

@connec
Copy link
Collaborator

connec commented Jun 29, 2017

I agree it's weird that -> and => have different arguments semantics.

We could go down the route of normalising that, but there are quite a few cases to consider as arrow functions also behave differently with respect to this and super, and possibly other subtle things. For example:

class A extends B
  f: ->
    setImmediate(=> super arguments...)

This would need to account for the fact that arguments can't appear in arrow functions, and super can't appear in regular functions, and do some kind of shenanigans...

var A

A = class A extends B {
  f () {
    return setImmediate((...args) => {
      return super.f(...args)
    })
  }
}

As you note, it gets even more interesting with arguments. For functions with super and arguments we would probably have to have a spread argument, pull out the values separately, and replace all occurrences of arguments with the spread.

We could choose instead to take the breaking change (possibly with a compiler error for arguments in fat arrow functions?).

@connec
Copy link
Collaborator

connec commented Jun 29, 2017

Re: your example @boris-petrov, I guess a workaround for now would be destructuring:

window.onerror = (args...) =>
  [ messageOrEvent, source, lineNumber, columnNumber, error ] = args
  @_notify(error)
  originalWindowError?(args...)

@boris-petrov
Copy link
Author

boris-petrov commented Jun 29, 2017

@connec - I agree, what you propose would fix my specific usecase, but if I were designing the language, I would strongly disagree with the idea that -> and => produce such different results. I didn't know that in ES6 arrow functions had such semantics about arguments and I think it doesn't make much sense and would confuse many people.

What I would do is I would preserve CoffeeScript 1 semantics - -> and => would differ only on the this binding and arguments would always have the "correct" value. I personally have a couple of examples where the new semantics don't make sense and I don't have a single case where the new one would be more useful.

I'm not the one to make decisions, but again - if it were up to me, I wouldn't take the reduce the barrier for users working in both languages way. People who write in both languages (we ALL do) would know the difference. What matters is what makes sense and what would make the language a better one. And I generally think ES6's approach doesn't do that.

P.S. Also, I think this will break a lot of code. Lots more than anything else that isn't backwards-compatible. I spent 10 minutes today fixing backwards-incompatible things (which were "compile"-time errors) and one or two hours going after the arrow stupidity of ES6.

@GeoffreyBooth
Copy link
Collaborator

When I was implementing the change to use the ES =>, one thing that came up with regard to arguments was that arguments can be inherited from the parent function:

var a = function (b, c) {
  var d = () => console.log(arguments);
  d();
}

a(1, 2);
// [1, 2]

So we can’t simply throw an error if we see a variable named arguments inside an arrow function. And we can’t redefine what variables named arguments mean or do, or else code like the above won’t behave as it should. We’re using the ES => now, and it means we use the ES => semantics.

What we should do is document this under http://coffeescript.org/v2/#breaking-changes, along with any other differences between the CS1 => and the CS2/ES =>.

@GeoffreyBooth GeoffreyBooth changed the title [CS2] Bug with using arguments in arrow function [CS2] Docs: Need to add breaking changes info about => differences in CS2 Jun 29, 2017
@boris-petrov
Copy link
Author

@GeoffreyBooth - I'm not sure what you mean by "or else code like the above won’t behave as it should". You are designing the language which means that you could make the code behave any way you want. :) Nobody says that => in CoffeeScript should compile down to =>. And, again, my personal opinion is that this behavior is not what one would expect. In JavaScript at least there is a major difference in syntax between function () { ... and => so one could argue that the difference in semantics concerning arguments is fine. But in CoffeeScript it is extremely minor - -> vs =>. I would expect => to be the same only with the this difference.

But anyway, I see that nobody likes my idea. :D If you prefer to leave it working as it is now, then yes, you should at least document it, as this is a big breaking change I think.

@GeoffreyBooth
Copy link
Collaborator

I’ll add it to the docs. I hear your point that we’re designing the language, but in many ways we’re not—if we want to be able to interoperate with ES2015 classes, for example, we need to use the class keyword, which means accepting ES2015’s more limited version of classes than CoffeeScript 1.x’s. From the beginning CoffeeScript has been defined as “just JavaScript,” and since JavaScript added the => operator, in order to be true to our principles we need to provide equivalence to it. The mission statement of CoffeeScript 2 spells this out explicitly.

GeoffreyBooth added a commit to GeoffreyBooth/coffeescript that referenced this issue Jun 30, 2017
@GeoffreyBooth GeoffreyBooth added this to the 2.0.0 milestone Jun 30, 2017
@boris-petrov
Copy link
Author

The "just JavaScript" idea has always been one of the very few things I don't like about CoffeeScript. :D But you are right that you have your mission statement and you have to follow it!

Thank you for everyone's time! We all appreciate your work on CoffeeScript! :)

@connec
Copy link
Collaborator

connec commented Jun 30, 2017

Thanks for bringing it to our attention, and for the well-reasoned, civil discourse 😄

GeoffreyBooth added a commit that referenced this issue Jun 30, 2017
* Don’t confuse the syntax highlighter

* Comment Assign::compilePatternMatch a bit

* Assignment expressions in conditionals are a bad practice

* Rename `wrapInBraces` to `wrapInParentheses`, to set the stage for future `wrapInBraces` that uses `{` and `wrapInBrackets` that uses `[`

* Correct comment

* object destructuring

* Allow custom position of the rest element.

* Output simple array destructuring assignments to ES2015

* Output simple object destructured assignments to ES2015

* Compile shorthand object properties to ES2015 shorthand properties

This dramatically improves the appearance of destructured imports.

* Don’t confuse the syntax highlighter

* Comment Assign::compilePatternMatch a bit

* Assignment expressions in conditionals are a bad practice

* Rename `wrapInBraces` to `wrapInParentheses`, to set the stage for future `wrapInBraces` that uses `{` and `wrapInBrackets` that uses `[`

* object destructuring

* Allow custom position of the rest element.

* rest element in object destructuring

* rest element in object destructuring

* fix string interpolation

* merging

* fixing splats in object literal

* Rest element in parameter destructuring

* merging with CS2

* merged with CS2

* Add support for the object spread initializer. https://github.com/tc39/proposal-object-rest-spread/blob/master/Spread.md

* Fix misspellings, trailing whitespace, other minor details

* merging with beta2

* refactor object spread properties

* small fix

* - Fixed object spread function parameters.
- Clean up "Assign" and moved all logic for object rest properties in single method (compileObjectDestruct).
- Add helper function "objectWithoutKeys" to the "UTILITIES" for use with object rest properties,
  e.g. {a, b, r...} = obj => {a, b} = obj, r = objectWithoutKeys(...)
- Clean up "Obj" and moved all logic for object spread properties in single method (compileSpread).
- Clean up "Code".
- Add method "hasSplat" to "Obj" and "Value" for checking if Obj contains the splat.
- Enable placing spread syntax triple dots on either right or left, per #85 (coffeescript6/discuss#85)

* Fixed typos

* Remove unused code

* Removed dots (e.g. splat) on the left side from the grammar

* Initial release for deep spread properties, e.g. obj2 = {obj.b..., a: 1} or {obj[b][c]..., d: 7}
Tests need to be prepared!

* 1. Object literal spread properties

Object literals:
- obj = { {b:{c:{d:1}}}..., a:1 }

Parenthetical:
- obj = { ( body ), a:1 }
- obj = { ( body )..., a:1 }

Invocation:
- obj = { ( (args) -> ... )(params), a:1 }
- obj = { ( (args) -> ... )(params)..., a:1 }
- obj = { foo(), a:1 }
- obj = { foo()..., a:1 }

2. Refactor, cleanup & other optimizations.

* Merged with 2.0

* Cleanup

* Some more cleanup.

* Fixed error with freeVariable and object destructuring.

* Fixed errors with object spread properties.

* Improvements, fixed errors.

* Minor improvement.

* Minor improvements.

* Typo.

* Remove unnecessary whitespace.

* Remove unnecessary whitespace.

* Changed few "assertErrorFormat" tests since parentheses are now allowed in the Obj.

* Whitespace cleanup

* Comments cleanup

* fix destructured obj param declarations

* refine fix; add test

* Refactor function args ({a, b...})

* Additional tests for object destructuring in function argument.

* Minor improvement for object destructuring variable declaration.

* refactor function args ({a, b...}) and ({a, b...} = {}); Obj And Param cleanup

* fix comment

* Fix object destructuring variable declaration.

* more tests with default values

* fix typo

* Fixed default values in object destructuring.

* small fix

* Babel’s tests for object rest spread

* Style: spaces after colons in object declarations

* Cleanup comments

* Simplify Babel tests

* Fix comments

* Fix destructuring with splats in multiple objects

* Add test for default values in detsructuring assignment with splats

* Handle default values when assigning to object splats

* Rewrite traverseRest to fix handling of dynamic keys

* Fix double parens around destructuring with splats

* Update compileObjectDestruct comments

* Improve formatting of top-level destructures with splats and tidy parens

* Added a bigger destructuring-with-defaults test and fixed a bug

* Refactor destructuring grammar to allow additional forms

* Add a missing case to ObjSpreadExpr

* These tests shouldn’t run in the browser

* Fix test.html

* Fix docs scroll position getting screwed up by CodeMirror initialization

* Breaking change documentation about => (fixes #4593)

* Spread/rest syntax documentation

* Documentation about bound class methods

* 2.0.0-beta3 changelog

* Add note about ‘lib’

* Fix accidentally converting this to tabs

* Bump version to 2.0.0-beta3

* Update annotated source and test.html
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants