- Notifications
You must be signed in to change notification settings - Fork2k
[CS2] Output ES2015 arrow functions, default parameters, rest parameters#4311
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
new(function(){})// Valid JavaScriptnew(()=>{})// Runtime error. Both tests should be removed, in my opinion. Are there no tests that include both fat arrows and parameter splats? I'd expect that to fail, since splats are implemented with a= (args...)=> args |
There's probably a whole debate to be had about whether we reallywant to output ES2015 arrow functions. I guess we do, but perhaps we should add special handling for |
Just another thought (forgive me if this is already handled in the PR): would we want to special-case single-JS-statement fat arrow functions and generate shorthand methods in that case? a==>console.log'hello'# var a = () => console.log('hello')a==>console.log'hello' ;console.log'world'# var a = () => {# console.log('hello')# console.log('world')# } |
@connec a=(..._arguments)=>{ ...} |
OK, I guess I was just wondering aloud whether or not we should continue to deal with E.g. what should this CS produce: ()=>arguments Currently it compiles to: function(){returnarguments;} With this change: ()=>{returnarguments;} Ultimately, would we want to catch calls to (..._arguments)=>{return_arguments;} |
I think it makes sense to simply disallow |
bjmiller commentedSep 20, 2016
I vote no for outputting es6 fat arrows. Original CS fat arrows are objectively better, and there is no advantage to having es6 arrows in the compiled code. Can everyone please stop trying to add es6 things to the compiled output just because they're new? |
@bjmiller I would be very interesting to hear what makes CS fat arrows better! :) |
Re the one-line syntax for arrow functions, I think we shouldn't bother. We don't output Re |
atg commentedSep 20, 2016
My intuition of CoffeeScript functions is that |
I wouldn't mind "banning" |
atg commentedSep 20, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Ipersonally would not mourn the loss of My view is that it's desirable for In some ways, ES6 arrows are worse. You can't So I agree with@bjmiller there's really nothing wrong with the way things currently work, and it has the added benefit of being compatible with ES3 and ES5 as well. |
If you want to create a bound generator function after this change, you would do so the same way in CoffeeScript as you would in ECMAScript: just declare What’s “wrong” with current arrow functions is that they unnecessarily deviate from the ES2015 spec. Now that JavaScript has arrow functions, we should output arrow functions. Anything else is counterintuitive. |
I was confused in my previous comments.
The second example returns an empty array, because of the I'm surprised that there were no tests for this! (Both examples above should of course log the same thing: |
GeoffreyBooth commentedSep 21, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
To complete@lydell’s example, here’s the ES2015 equivalent: console.log(((...a)=>a)(1,2,3))// [1, 2, 3] So thereis a way to access a limitless number of arguments in an arrow function, so long as we make sure to compile That just leaves the generator issue. Is it really so common to make a bound function generator? Is |
…arameter syntax) output that parameter as ES2015
GeoffreyBooth commentedSep 25, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Okay@lydell, I did some work on splats/rest parameters. I could do a lot more to eliminate now-unnecessary code, but I just want to get this working first. Anyway, as of my latest commit your example: a= (args...)=> args becomes vara;a=(...args)=>{returnargs;}; Since we’re not converting ./bin/coffee -e'console.log(((a...) => a) 1, 2, 3)'[ 1, 2, 3 ] An interesting disadvantage of the ES2015 rest parameter syntax is that the rest parameter must be thelast parameter. So now we have two failing tests:
That This also raises the question of what to do about expansions in parameter lists:
|
Yes, splats have to be thelast thing in ES. My first idea for handling that (rather than dropping support) was to do something like: f= (a,b,args...,c,d)-> f=function(a,b,c,d, ...args){[c,d]=args.slice(-2);args=args.slice(0,-2);}; Also, could you merge |
GeoffreyBooth commentedSep 25, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
The diff should be sensible now. Your example doesn’t work for me: f=function(a,b,c,d, ...args){[c,d]=args.slice(-2);args=args.slice(0,-2);console.log(a,b,args[0],c,d);};f(1,2,3,4,5)// 1 2 undefined 5 undefined
We can, however, recreate f=function(a,b,c,d, ...args){letarguments=[a,b,c,d].concat(args);[c,d]=arguments.slice(-2);args=arguments.slice(2,-2);console.log(a,b, ...args,c,d);};f(1,2,3,4,5)// 1 2 3 4 5f(1,2,3,4,5,6,7)// 1 2 3 4 5 6 7 I guess the question is whether we should. This strikes me as a lot of extra JavaScript to be outputting. I suppose we should do it to prevent breaking backward compatibility, but it feels messy. It’s also so much more difficult to figure out: the |
Better version without intermediate variable: f= (a,b,args...,c,d)=>console.log a, b, args..., c, d becomes: f=(...args)=>{[a,b]=args.slice(0,2);[c,d]=args.slice(-2);args=args.slice(2,-2);console.log(a,b, ...args,c,d);} And This is quite complicated to produce, so the question still stands: is this a feature we want to support? Likewise with expanding parameters: f= (a,...,b)=> This isn’t even mentioned in the docs, though it’s in the grammar. Are we keeping this too? |
lydell commentedSep 26, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Sorry about that broken compilation example. It sure was a "something like." Here's a version that I've actually tested: varf;f=function(a,b,c,d, ...args){[c,d, ...args]=args.slice(-2).concat([c,d],args.slice(0,-2))} Regarding that it is more complicated to compile: Yes, it is. But at the same time, that's what we've been doing here for like half a decade now. Regarding whether the feature is useful or not: I can't really think of a case (from the top of my mind) when I've used a splat parameter somewhere else than at the end. However, Ihave used it in Regarding Regarding your suggested compilation: Summary:
|
Here's an example with parameter defaults: // f = (a = 1, b = 2, args..., c = 3, d = 4) ->varf;f=function(a=1,b=2,c,d, ...args){[c=3,d=4, ...args]=args.slice(-2).concat([c,d],args.slice(0,-2))console.log(a,b,args,c,d)} And here's an example with destructuring: // f = ({a = 1} = {}, b, args..., c, d) ->varf;f=function({a=1}={},b,c,d, ...args){[c,{d=4}={}, ...args]=args.slice(-2).concat([c,d],args.slice(0,-2))console.log(a,b,args,c,d)} |
I was only referring to function parameters. Limiting splats to the last argument in a function parameter list, the way ES does, doesn’t mean we would need to stop using splats in any position in destructuring. Assuming splats elsewhere are untouched, are you still sure we want to support splats at any function parameter position? And expansions at any function parameter position? |
I've never been sure :) Personally, I wouldn't mind dropping splats at any position in parameter lists. And dropping expansion in parameter lists. The only "bad" thing is that array destructuring and "parameter list destructuring" would no longer be equivalent. The following would no longer be true: f= (<params>)-># equivalent to:f= (args...)-> [<params>]= args Couldn't we use the same code in both cases? Another route we could take, is to:
|
@connec@jashkenas@lydell Not to short-circuit the discussion incoffeescript6/discuss#51, but can we merge in this PR as is? And if we ultimately decide to go the other way regarding |
If merging this helps you who actually work on the 2 branch, then go for it, I'd say. The 2 branch doesn't need be be as stable as master. |
So I just tried running the tests in this branch under test"bound generator",->obj=bound:->do=>yieldthisunbound:->do->yieldthisnested:->do=>yielddo=>yielddo=>yieldthis It only fails in harmony mode because we’re not running Anyway the reason this test fails is because of the f==>yieldthis compiles (via this PR) to this: f=()=>{return(yieldthis);}; which Node doesn’t like: return(yieldthis);^^^^SyntaxError:Unexpectedtokenthis becausearrow functions cannot be generators. So this is another breaking change as a result of this PR. And I need to find a way to check that The workaround, ironically enough, is to just use a regular function and the old self=thisf=->yield self |
… add check to throw error if `yield` appears inside a bound (arrow) function
Fixed. Everyone okay with this change? I suppose the alternative is to fall back to the CS 1.x output for bound functions in the event of a bound generator function, but I feel like that will cause more debugging trouble than it’s worth, by potentially introducing inconsistencies between bound functions with and without @lydell, others, is there anything I’m missing here? If not, please let me know and I’ll merge this PR into |
assertErrorFormat 'f = => yield this', ''' | ||
[stdin]:1:5: error: bound (fat arrow) functions cannot contain 'yield' | ||
f = => yield this | ||
^^^^^^^^^^^^^ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
What will this look like if the function is multi-line? Is it better to underlineyield
only?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
It just underlines whatever the first line of the function is, starting at the=>
:
./bin/coffee -bpe 'f = =>quote> 1quote> 2quote> yield this'[stdin]:1:5: error: bound (fat arrow) functions cannot contain 'yield'f = => ^^
Updated. Now it only underlines the
|
@lydell any other notes? |
lydell commentedOct 26, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
No :) |
WIP. Just thought I’d get the ball rolling and try to establish a precedent for merging into the
2
branch. I’ve only spent a few minutes on this, and I was surprised how easy it was to get=>
to output as=>
; although I get the sense that there are a lot of considerations to=>
that I’m not considering. Please enlighten me.Only two tests fail with this patch, but I’m not sure that they should pass:
@lydell actuallycommented back when he wrote the second test that it would fail when we output
=>
. So maybe it’s time to remove that test?As for the first one, I get the sense that the test was written expecting the arrow function to be wrapped by an IIFE. I presume that the point of outputting
=>
for=>
is to get our output closer to its input, and therefore we shouldn’t be dropping unexpected wrapper functions into the output:./bin/coffee -bpe'foo = (bar) => console.log bar, @'
Is this correct? Or should this test pass somehow?
There must be lots of additional code scattered across the repo that can be removed now that we needn’t do so much work to parse
=>
. What cleanup needs to be done?