-
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
Fix #4876: remove polyfill for object rest/spread #4884
Conversation
We can’t merge this with commented-out tests. If the tests are no longer valid, they should be removed; but looking at them, I’m wondering if we should instead try to make them pass. Take the simplest case: {{g}...} = g: 1 var g;
({...{g}} = {
g: 1
}); This throws h = {g}
{h...} = g: 1 var h;
h = {g};
({...h} = {
g: 1
}); This doesn’t throw any errors, and should be equivalent to the first example unless I’m missing something. So I’m thinking, if all we need to do to avoid this “must be followed by an assignable reference” error is to make a reference to the assignment target, couldn’t the compiler do that automatically? As in: {{g}...} = g: 1 var g, ref;
ref = {g};
({...ref} = {
g: 1
}); We already have lots of functions for creating temporary “reference” variables. Let’s try to use them to see if we can avoid a potential breaking change. One last thought: what’s going on here? {({g})...} = g: 1 var g, ref,
slice = [].slice;
ref = {
g: 1
}, {g} = slice.call(ref, 0); |
Different question, for @jashkenas and @lydell and @connec and @vendethiel and other interested parties: How would you all feel if we dropped support for Node 6? As you can see in the build log, there are a fair number of tests scattered around that don’t parse in Node 6 after this PR; though the compiler itself still never uses object spread/destructuring, so it runs in Node 6 even if some of the tests fail. To keep support for Node 6, we would need to refactor the tests to silo off the object destructuring ones into files that aren’t loaded in Node < 8, similar to how we have the async tests. But I’m wondering if that’s worth the effort, versus just dropping Node 6 and keeping the codebase simpler. See also #4881; as we add more Node 8+, ES2018+ features, this will be an increasingly common issue. I think I lean toward the side of keeping support for Node 6, even in tests, even if it means more complication in moving test files around; but I feel like we should discuss it. |
I havn't used nodejs as a platform myself for too long to have an informed opinion, sorry. |
Both I'm not sure if there is any value of supporting this syntax, because var ref, a;
({...ref} = obj);
({...a} = ref); Or, perhaps this example var ref, ref1, a, b, c, d, e;
({a, ...ref} = obj);
({b, c, ...ref1} = ref);
({d, ...e} = ref1); I would propose alternative solution, e.g. stripping redundant But then, what about this {ref...} = obj
a = [ref]
# or
a = [{a...} = obj]
# or
a = [obj] A more complex example: obj = {a: 1, b: 2, c:3, d: 4}
{a, b, {[x]...}...} = obj
# should compile to?
{a, b, ...ref} = obj
x = [ref]
###
a = 1
b = 2
x = [{c: 3, d: 4}]
### I might be missing something, but it seems to much work and trouble. @GeoffreyBooth |
I think support for Node 6 shouldn't be dropped. The end of life is scheduled for April 2019, and there are projects still running on this version. I followed the path of |
This seems to be a stage 3 thing in babel (though it seems to work without transpilation in everything not IE) The active support date for node 6 is end of march 2018, so if we're to drop node 6 support, I'd suggest just lumping #4880, #4881, #4884, #4994, and #5006 together and call it version 2.5. There are enough syntax additions that it warrants skipping a few versions. If there's any weird bugs that remain on 2.2.x maybe we can just backport the fixes? That is assuming the branches don't diverge that much in the year that node 6 has left on its 'maintenance' lifespan. Also doing a semi-major version bump can indicate that underlying philosophy has changed and that we're now merging in features that are marked stage 3 on babel. |
This feature is Stage 4. I see no reason to skip versions or maintain separate forks. The compatibility info is for convenience, not a promise; it's up to the user to ensure that their code runs in whatever runtime or browser they want to run it in, or they should transpile. |
# Conflicts: # Cakefile
# Conflicts: # Cakefile
src/nodes.coffee
Outdated
@@ -2216,9 +2203,6 @@ exports.Assign = class Assign extends Base | |||
# Check if @variable contains Obj with splats. | |||
hasSplat = @variable.contains (node) -> node instanceof Obj and node.hasSplat() | |||
return @compileDestructuring o if not @variable.isAssignable() or @variable.isArray() and hasSplat |
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.
@zdenko can you remove or @variable.isArray() and hasSplat
? So that now eg
[{...a}] = b
would compile to [{...a}] = b
instead of ({...a} = b[0])
?
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.
Done.
src/nodes.coffee
Outdated
idt = o.indent += TAB | ||
lastNode = @lastNode @properties | ||
|
||
# CSX attributes <div id="val" attr={aaa} {props...} /> | ||
return @compileCSXAttributes o if @csx | ||
|
||
if @hasSplat() and @lhs |
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.
why not do this check in @reorderProperties
?
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.
Nice catch. Thanks.
5d2c76c
to
3a17c53
Compare
src/nodes.coffee
Outdated
fragments.pop() | ||
|
||
fragments | ||
|
||
# Brief implementation of recursive pattern matching, when assigning array or | ||
# object literals to a value. Peeks at their properties to assign inner names. | ||
compileDestructuring: (o) -> |
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.
@zdenko I believe you can also stop treating object spreads as complexObjects()
in compileDestructuring()
? So eg [..., {r...}] = arr
compiles to
[{...r}] = slice.call(arr, -1);
instead of
ref = slice.call(arr, -1), ({...r} = ref[0]);
If so, not sure exactly what code inside compileDestructuring()
can be removed, at least the stuff related to hasObjSpreads()
?
ca0b847
to
6133f17
Compare
Last commit fixes unassignable rest properties, e.g. {{a...}...} = b
# ({...ref} = b), ({...a} = ref); f = ({{a...}...}) ->
###
f = function(arg) {
var a, arg, ref;
({...ref} = arg), ({...a} = ref);
};
### |
I see no point allowing it |
@helixbass What does var fn = function(...{a}) { return a; }; into Chrome console but no matter what I pass into |
@GeoffreyBooth try The splatted param is an array, so that's about the only way I see to meaningfully treat the array as an object If getting rid of it seems reasonable(/acceptably breaking if anyone has actually used it), seems like throwing an error in |
Although I figure it's against our policy to not support a destructuring syntax that's supported in ES6. And that it'd be strange/more work than it's worth to allow it in the simple case |
Yes, in general we want to be able to output any valid JS, aside from known exclusions like So you’re saying that really literally only (function(...{length}) { return length; })(1, 'b', null) returns |
@GeoffreyBooth that stance would make sense if we didn't already support it. But my understanding of the current status is that the simple case (eg |
@helixbass I’m not following. Can you please explain with examples? |
@zdenko Do you think we should make the change @helixbass is proposing? Separate question: I’m considering whether to release 2.3.0 with the PRs that have been merged in so far plus this one, and leave the completely new features (supporting accessors without brackets, “sub-structuring”) as a potential 2.4.0. This would give the ES2018 stuff its own release, and a period of potential patches separate from the new functionality. Thoughts? |
Yes, I think @helixbass is right. This PR already outputs object splats (
That's a good call. I agree. ES2018 stuff in 2.3.0, and new features later in 2.4.0. |
@zdenko @GeoffreyBooth I pushed a commit to my @zdenko brought up a good point which is that the corresponding assignment cases (as opposed to function params) also should be covered. Turned out that both array-destructured and object-destructured non-final splats (in array destructuring assignments) were both broken (and not covered by my suggested fix). Eg both of these were failing but are now passing: [{length}..., three] = [1, 2, 3]
eq length, 2
eq three, 3 [[one, two]..., three] = [1, 2, 3]
eq one, 1
eq two, 2
eq three, 3 For the param cases, the fix I suggested above (adding f = ({length}..., last) -> [length, last]
arrayEq f(4, 5, 6), [2, 6] Let me know if you have any other questions about what I committed or what’s covered, thanks |
@helixbass it seems we're both working on the same stuff at the same time 😄 [x, {a}..., y] = [1, {a: 42}, 2]
# x = 1
# a = 42
# y = 2 IMO, this desugars into [x, r..., y] = [1, {a: 42}, 2]
{a} = r |
@zdenko I think your example has the right idea for translating Currently my branch compiles your example into:
Not sure why there's the additional caching to
|
x = 1
y = [ { a: 42 } ]
a = undefined Instead of |
@zdenko no, it should agree with ES meaning of But it is definitely an object-dereferencing of an array (the splatted array), not an object-dereferencing of the first element of an array |
I suppose you could technically pluck arguments at index, i.e. |
In that case should we allow This PR desugars Examples: arr = [1, {a: 42, b: 43}, 2, 3, 4]
[x, {a}..., y, z] = arr
# x = 1, a= 42, y = 3, z = 4 foo = (x, {a}..., y, z) -> [x, a, y, z]
[x, a, y, z] = foo 1, {a:42}, 2, 3, 4
# x = 1, a= 42, y = 3, z = 4 |
@zdenko I'm indifferent to allowing object-destructuring of an object rest spread (eg But as far as making object-destructuring of an "array splat" implicitly dereference the first element of the array, that's a very bad idea, let me explain Start from the difference between the two types of destructured/left-hand-side splats: when the splat is inside an object, it's an "object rest spread" and the splat variable will be an object (eg So we are discussing the "array splat" case only, and specifically when the splat variable is itself a destructured object. You are saying the object that gets destructured should be the first element of the array splat and I'm saying it should be the array splat itself. Eg whether Here are my reasons why it should be the latter (object-dereference the array splat itself):
To illustrate ES6 behavior, run these in Chrome console or wherever:
and the corresponding array-destructured assignments:
Existing Coffeescript behavior matches ES6 behavior, eg And as far as intuitive/expected behavior, it's clearly a confusing syntax regardless. I imagine that your arguments for making it dereference the first element of the array splat are that it may be more useful (since the use cases for object-dereferencing an array are very limited), may seem more consistent with the meaning of But that "consistency" is not a valid point, as clearly As far as expected meaning, clearly our brain may think " But so then it should be clear how to achieve the desired effect of dereferencing the first element of the array splat: just wrap the object-destructuring in So to me it is clear that compatibility with ES6, compatibility with existing Coffeescript behavior, and maintaining this implicit rule of destructuring-syntax precision are more than enough reasons to prefer the meaning "object-destructure the array splat itself" over "object-destructure the first element of the array splat" If you see my argument, I'd encourage you to use the commit on my |
@helixbass you made a very sound argument. I was indeed looking at |
Is there anything holding up this PR? |
16ffeb0
to
e0b8aed
Compare
e0b8aed
to
b2a027e
Compare
@GeoffreyBooth I think it's ready to be merged. |
@zdenko @GeoffreyBooth lgtm |
Thanks much @zdenko and @helixbass. I’ll prepare a new release soon. |
Fixes #4876. This PR removes polyfills for object rest/spread syntax.
The
rest
property can be positioned anywhere. In the compiled code it will be moved at the end:I commented a few existing tests since it seems the following code isn’t valid: