This repository was archived by the owner on Feb 22, 2018. It is now read-only.
This repository was archived by the owner on Feb 22, 2018. It is now read-only.
Named arguments that are reserved ES6 keywords cannot be destructured #392
Closed
Description
Right now we rename variables only. With destructuring of args (#180), looks like we would hit issues with reserved keywords:
main() {
void f({delete, function}) {
print("delete: $delete");
print("function: $function");
}
f(delete: 1, function: 2);
}
Would give some syntax-error-full code:
function main() {
function f({delete = null, function = null} = {}) {
core.print(`delete: ${delete}`);
core.print(`function: ${function}`);
}
f({delete: 1, function: 2});
}
(note: compiler currently works fine, issues are only with destructuring of named args)
Activity
jmesserly commentedon Dec 2, 2015
@ochafik we shouldn't rename those. It can be written in a JS friendly way like this:
The bug here is in js_ast's handling of object literals.
In general, one thing to keep in mind with JS: it's fine to have almost any name as a field of an object. The naming restrictions apply for locals (as you can see, they were both renamed).
We also need to avoid whenever possible renaming top-level things. Those are part of the API, part of the module object, and should keep their names. In other words, renaming is a last resort.
[-]Need to rename named arguments that are reserved ES6 keywords[/-][+]Named arguments that are reserved ES6 keywords are not working[/+]jmesserly commentedon Dec 2, 2015
actually, wait a minute. The current code works just fine (try this in the console):
The compiler at one point did quote these, (printer.dart, propertyNameOut) but it is not needed in ES6 (and I believe this was true in ES5 as well).
jmesserly commentedon Dec 2, 2015
oops hit send too soon. Did you see an actual problem? Or it just didn't look right to you?
jmesserly commentedon Dec 2, 2015
from the spec:
Reserved Words
Object Initializer
ochafik commentedon Dec 2, 2015
Actually sorry, these identifiers only cause issues in some situations (roughly, as lvalues), one of which would be destructuring of named arguments (#180):
(edited description accordingly)
ochafik commentedon Dec 2, 2015
So, if we prioritize preservation of named args, this means we can't use param destructuring in those cases.
But note that destructuring solves other issues, like the mix of string & identifier we have right now (which hinders Closure's advanced optimizations #311):
let b = opts && 'b' in opts ? opts.b : null;
I'm biased but I would prioritize destructuring and would rename
function
and other reserved words when used as named params... WDYT? (hopefully, shouldn't happen too often anyway)jmesserly commentedon Dec 2, 2015
IMO, we should always prioritize generating code with the right APIs. That way the code does what the developer intended. Otherwise there are some JS argument names you can't express correctly in Dart. Thus far, we try and rename as an absolute last resort (and most of the cases are around local variables, where it doesn't leak into the APIs).
I'm not familiar enough with Closure's advanced opts to know what to do, but surely there's a pattern of some sort that works for JS named arguments (that doesn't rely on just-implemented ES6 destructuring). And if not, we could do more good for the JS world by improving Closure than handicapping DDC's output.
jmesserly commentedon Dec 2, 2015
regarding:
this works:
IIRC, the ambiguity existed in ES5. It's because
{ foo: ...
could be a block with a label on the first statement. So open curly at that level of the grammar is always parsed as the start of a block (http://www.ecma-international.org/ecma-262/6.0/#sec-statements). This comes up in the context of arrow functions too. If you want to return an object literal, you have to write:(x, y) => ({ foo: x, bar: y })
instead of(x, y) => { foo: x, bar: y }
, as the latter is a block function body, not an object literal.ochafik commentedon Dec 2, 2015
Ah, true, parenthesis save the top-level case, but they're not accepted in function params :-S
(
function f(({function})) {}
).I'll just drop out of destructuring when any param has a reserved name then, thanks!
(thanks for the context! starting to get why some people thought they'd be better off writing a new language from scratch ;-))
jmesserly commentedon Dec 2, 2015
yeah, that makes sense. The object destructuring needs to work as both a local variable, as well as for an object property, since it's sort of like doing
let b = opts && 'b' in opts ? opts.b : null;
in one step. Except for things likefunction
we were handling that by renaming the locallet func = opts && 'function' in opts ? opts.function : null;
. I guess destructuring can't express the second one. Some systems can support that, often with an "as" (like how imports can be renamed). So it'd befunction foo({function as func} = {})
but I'm guessing ES6 didn't include that feature.[-]Named arguments that are reserved ES6 keywords are not working[/-][+]Named arguments that are reserved ES6 keywords cannot be destructured[/+]ochafik commentedon Dec 2, 2015
The aliasing syntax you suggest would be neat & consistent with the import syntax... (hehe, "just" have to file a request for ES7?)
(closing this question, will link to it from the destructuring drop-out logic)
# This is a combination of 4 commits.
Before (for `f(a, {b, c: c_default})`):
Before (for `f(a, {b, c: c_default})`):