let and strict mode
On Nov 15, 2012, at 11:33 AM, Kevin Smith wrote:
I'm not quite sure how to figure this out from the current draft, but is "let" only available from strict mode code? This is valid under ES5 non-strict via ASI:
No, it is currently spec'ed as a reserved keyword in both regular and strict mode.
This is what TC39 agreed to try when we started down the 1JS path, with the expectation that implementation would explore the compatibility impact.
If necessary, we should be able to make "let" a contextual keyword (only recognized as a statement head) followed by a [no LineTerminator here] in order to take care of the ASI case you show below.
On Thu, Nov 15, 2012 at 2:49 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:
This is what TC39 agreed to try when we started down the 1JS path, with the expectation that implementation would explore the compatibility impact.
JSC tried making let a keyword and it broke things, forcing them to revert that.
Of course, 'let' short for 'letter' :-|.
Contextual keyword with [no LineTerminator here] after sounds like the plan. I'm curious whether you have already implemented this in Traceur?
On Nov 15, 2012, at 4:17 PM, Brendan Eich wrote:
Of course, 'let' short for 'letter' :-|.
Contextual keyword with [no LineTerminator here] after sounds like the plan. I'm curious whether you have already implemented this in Traceur?
/be
I wonder if the [no LineTerminator here] is really need in practice?
How often does
/* whatever*/ ;
let
x = "abc";
actually occur in real code??
(I'm assuming that the JSC test was just making "let" a reserved id rather than a contextual keyword)
On Fri, Nov 16, 2012 at 1:35 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
On Nov 15, 2012, at 4:17 PM, Brendan Eich wrote:
Of course, 'let' short for 'letter' :-|.
Contextual keyword with [no LineTerminator here] after sounds like the plan. I'm curious whether you have already implemented this in Traceur?
/be
I wonder if the [no LineTerminator here] is really need in practice?
How often does
/* whatever*/ ; let x = "abc";
actually occur in real code??
Um, if that's a concern, I often see multiple var declarations start with a newline after var, to line up all the variable names (including the first)...
var
foo=1,
bar=2,
zee=...;
Allen Wirfs-Brock wrote:
On Nov 15, 2012, at 4:17 PM, Brendan Eich wrote:
Of course, 'let' short for 'letter' :-|.
Contextual keyword with [no LineTerminator here] after sounds like the plan. I'm curious whether you have already implemented this in Traceur?
/be
I wonder if the [no LineTerminator here] is really need in practice?
How often does
/* whatever*/ ; let x = "abc";
actually occur in real code??
Who knows? We can chance it but should we? Optimize by daring fate, prototyping and spec'ing in draft-ES6, and if we get bad news late in the process, change course. I like it if the optimization wins. If it loses....
(I'm assuming that the JSC test was just making "let" a reserved id rather than a contextual keyword)
Right.
On Nov 15, 2012, at 4:44 PM, Brendan Eich wrote:
Allen Wirfs-Brock wrote:
On Nov 15, 2012, at 4:17 PM, Brendan Eich wrote:
Of course, 'let' short for 'letter' :-|.
Contextual keyword with [no LineTerminator here] after sounds like the plan. I'm curious whether you have already implemented this in Traceur?
/be
I wonder if the [no LineTerminator here] is really need in practice?
How often does
/* whatever*/ ; let x = "abc";
actually occur in real code??
Who knows? We can chance it but should we? Optimize by daring fate, prototyping and spec'ing in draft-ES6, and if we get bad news late in the process, change course. I like it if the optimization wins. If it loses....
Another experiment would tell us more...and as Peter points out, there are people who like to put their declarator keyword on a separate line.
Another experiment would tell us more...and as Peter points out, there are people who like to put their declarator keyword on a separate line.
Mmm... I think a [no LineTerm] restriction is going to bite too hard in this case. If "let" in non-strict mode were a context-sensitive keyword, with a restriction that limits the lookahead to first tokens in binding patterns, what kind of code would break?
<some arbitrary statement or nothing> let
(ident | "{" | "[") <some sequence of tokens>
So the only code that would break would be expression statements consisting of the single identifier "let", followed by an ASI'd newline. Is that right?
If there's any working code out there like that, then it deserves to break : )
So the only code that would break would be expression statements consisting of the single identifier "let", followed by an ASI'd newline. Is that right?
To reply to myself, there's also this:
var let = [], num = 0;
let[num] = f();
Hmmm....
I suppose a radical but safe solution would be to only allow let in strict mode. A carrot (or stick, depending on your point of view) to get users into strict?
Kevin Smith wrote:
var let = [], num = 0; let[num] = f();
Awww, that's hard. I am really curious how this one is solved.
Doesn't the same problem exist with:
var let = function() {};
let();
Or:
var let = { it: "be" };
let.it // be
Yehuda Katz wrote:
Doesn't the same problem exist with:
var let = function() {}; let();
Or:
var let = { it: "be" }; let.it // be
These seem to be parseable better (especially the latter), but how to distiguish if
let [foo] = bar
is let
with destructuring or assignment with index?
On Fri, Nov 16, 2012 at 9:19 AM, Herby Voj??k <herby at mailbox.sk <mailto:herby at mailbox.sk>> wrote:
Kevin Smith wrote: var let = [], num = 0; let[num] = f(); Awww, that's hard. I am really curious how this one is solved. - Kevin Herby
-- Yehuda Katz (ph) 718.877.1325
var let = function() {}; let();
If let is a contextual keyword (in non-strict mode of course), then we can
look ahead to the token after let
to validate it. An open paren cannot
follow a let keyword, so therefore it must be an identifier.
var let = { it: "be" }; let.it // be
Same logic applies. A dot cannot follow a let keyword so we parse it as an identifier.
On the other hand, an open square bracket can follow a let keyword (by array destructuring), so we have a potential ambiguity there.
- Kevin -------------- next part -------------- An HTML attachment was scrubbed... URL: esdiscuss/attachments/20121116/c945ad35/attachment
Dave Herman proposed as part of 1JS that module imply strict mode, so let is reserved in module. So that helps.
For let outside of modules, we could contextually parse let at start of statement if followed by an identifier or a { that starts an object pattern. We could even allow LineTerminator after let, and perhaps should try to get away with that.
But if we allow LineTerminator and risk some backward incompat, can we up the ante by allowing [ after let?
Who knows, but we have some choices:
-
'let' only in strict code including modules per 1JS as originally proposed.
-
'let' followed by identifier or { but not LineTerminator.
-
'let' followed by identifier or { with LineTerminator and other space allowed in between.
-
'let' followed by identifier, {, or [ and LineTerminator in between is ok.
-
We could also allow 'let' per (4) in functions not in modules that do not "use strict" but do use new ES6 syntax in their heads, e.g. destructuring parameters, default parameters, rest parameters. Those head features could arguably opt into 'let' syntax but not strict mode.
Comments?
On Sat, Nov 17, 2012 at 6:06 PM, Brendan Eich <brendan at mozilla.com> wrote:
Dave Herman proposed as part of 1JS that module imply strict mode, so let is reserved in module. So that helps.
For let outside of modules, we could contextually parse let at start of statement if followed by an identifier or a { that starts an object pattern. We could even allow LineTerminator after let, and perhaps should try to get away with that.
But if we allow LineTerminator and risk some backward incompat, can we up the ante by allowing [ after let?
Who knows, but we have some choices:
- 'let' only in strict code including modules per 1JS as originally proposed.
This would essentially be sending the message: "get your ES5 house in order before trying to use ES6 binding forms". I'm not sure how I feel about this, but getting people to clean up code invalid in ES5 strict mode is a nice carrot.
'let' followed by identifier or { but not LineTerminator.
'let' followed by identifier or { with LineTerminator and other space allowed in between.
'let' followed by identifier, {, or [ and LineTerminator in between is ok.
Trying to identify let
usage by known ES6 syntax could be future hostile,
by limiting our ability to extend the BindingList grammar. It would
essentially restrict us from adding any prefixes to BindingIdentifier that
could be ambiguous in ES5. I'm not fully enough aware of all of the
historical proposals to know whether any of these could become issues in
the future: let ?foo
, let ^foo
, let &foo
. Maybe there's something I'm
missing and this category of problem could not arise?
- We could also allow 'let' per (4) in functions not in modules that do not "use strict" but do use new ES6 syntax in their heads, e.g. destructuring parameters, default parameters, rest parameters. Those head features could arguably opt into 'let' syntax but not strict mode.
I'd be worried that it would confusingly break refactored code:
function isPermitted(user) {
var permissions = [].slice.call(arguments, 1),
let = authorize(permissions);
if (!let) { return false; }
else return permissions;
}
// to
function isPermitted(user, ...permissions) {
var let = authorize(permissions);
if (!let) { return false; }
else return permissions;
}
Comments?
/be
Kevin Smith wrote:
var let = function() {}; let();
If let is a contextual keyword (in non-strict mode of course), then we can look ahead to the token after
let
to validate it. An open paren cannot follow a let keyword, so therefore it must be an identifier.var let = { it: "be" }; let.it <http://let.it> // be
Same logic applies. A dot cannot follow a let keyword so we parse it as an identifier.
On the other hand, an open square bracket can follow a let keyword (by array destructuring), so we have a potential ambiguity there.
- Kevin
_____________** es-discuss mailing list es-discuss at mozilla.org, mail.mozilla.org/**listinfo/es-discussmail.mozilla.org/listinfo/es-discuss
-- Yehuda Katz (ph) 718.877.1325 -------------- next part -------------- An HTML attachment was scrubbed... URL: esdiscuss/attachments/20121117/3c87fc28/attachment
Yehuda Katz wrote:
On Sat, Nov 17, 2012 at 6:06 PM, Brendan Eich wrote:
Dave Herman proposed as part of 1JS that module imply strict mode, so let is reserved in module. So that helps.
For let outside of modules, we could contextually parse let at start of statement if followed by an identifier or a { that starts an object pattern. We could even allow LineTerminator after let, and perhaps should try to get away with that.
But if we allow LineTerminator and risk some backward incompat, can we up the ante by allowing [ after let?
Who knows, but we have some choices:
- 'let' only in strict code including modules per 1JS as originally proposed.
This would essentially be sending the message: "get your ES5 house in order before trying to use ES6 binding forms". I'm not sure how I feel about this, but getting people to clean up code invalid in ES5 strict mode is a nice carrot.
Yes, this is the simplest and safest course.
'let' followed by identifier or { but not LineTerminator.
'let' followed by identifier or { with LineTerminator and other space allowed in between.
'let' followed by identifier, {, or [ and LineTerminator in between is ok.
Trying to identify
let
usage by known ES6 syntax could be future hostile, by limiting our ability to extend the BindingList grammar. It would essentially restrict us from adding any prefixes to BindingIdentifier that could be ambiguous in ES5. I'm not fully enough aware of all of the historical proposals to know whether any of these could become issues in the future: let ?foo, let ^foo, let &foo. Maybe there's something I'm missing and this category of problem could not arise?
Good points, especially ? as prefix, although we seemed to agree that patterns are irrefutable (match undefined), so a refutable option might prefer prefix-! to imply a "cut" (throw in a binding form; try next pattern in a multi-match construct).
- We could also allow 'let' per (4) in functions not in modules that do not "use strict" but do use new ES6 syntax in their heads, e.g. destructuring parameters, default parameters, rest parameters. Those head features could arguably opt into 'let' syntax but not strict mode.
I'd be worried that it would confusingly break refactored code:
function isPermitted(user) { var permissions = [].slice.call(arguments, 1), let = authorize(permissions); if (!let) { return false; } else return permissions; } // to function isPermitted(user, ...permissions) { var let = authorize(permissions); if (!let) { return false; } else return permissions; }
Yes, this is a downside. I don't favor (5) on this account. New syntax is its own opt-in but using a rest parameter should not opt the whole body into a different piece of new syntax.
/be
Personally, the fact that modules opt in to strict mode completely obviates the problem for me. I anticipate this to be the case for most "non-beginner" ES programmers as well, since they are largely using either a CommonJS-like or an AMD module system, and as part of an ES6 migration would then move to ES6 modules. (Note: perspective bias probably in play here.) Even for future-beginners, i.e. beginners in a post-ES6 world, they will presumably be taught to always use modules.
Of course it remains important to specify exactly which course you guys want to take, but I just wanted to provide some perspective that the exact solution for non-strict code is probably, hopefully, not terribly impactful. I guess this could be an argument toward (1)?
Dave Herman proposed as part of 1JS that module imply strict mode, so let is reserved in module. So that helps.
Sure, for inline modules. But are externally loaded modules strict as well? I think they should be...
'let' only in strict code including modules per 1JS as originally proposed.
'let' followed by identifier or { but not LineTerminator.
'let' followed by identifier or { with LineTerminator and other space allowed in between.
'let' followed by identifier, {, or [ and LineTerminator in between is ok.
We could also allow 'let' per (4) in functions not in modules that do not "use strict" but do use new ES6 syntax in their heads, e.g. destructuring parameters, default parameters, rest parameters. Those head features could arguably opt into 'let' syntax but not strict mode.
Anything other than (1) neuters either the let statement or let identifiers
-
yuck. As Domenic says, most new code will go in modules anyway.
-
Kevin -------------- next part -------------- An HTML attachment was scrubbed... URL: esdiscuss/attachments/20121118/590fca31/attachment
Question: does requiring strict mode for changes that break compatibility with ES5 really address the 1JS concerns? We're making usages of the identifier let that were valid in ES5 strict invalid in ES6 strict. Doesn't that violate 1JS?
On Sun, Nov 18, 2012 at 7:02 AM, Kevin Smith <khs4473 at gmail.com> wrote:
Dave Herman proposed as part of 1JS that module imply strict mode, so let
is reserved in module. So that helps.
Sure, for inline modules. But are externally loaded modules strict as well? I think they should be...
- 'let' only in strict code including modules per 1JS as originally
proposed.
'let' followed by identifier or { but not LineTerminator.
'let' followed by identifier or { with LineTerminator and other space allowed in between.
'let' followed by identifier, {, or [ and LineTerminator in between is ok.
We could also allow 'let' per (4) in functions not in modules that do not "use strict" but do use new ES6 syntax in their heads, e.g. destructuring parameters, default parameters, rest parameters. Those head features could arguably opt into 'let' syntax but not strict mode.
Anything other than (1) neuters either the let statement or let identifiers - yuck. As Domenic says, most new code will go in modules anyway.
- Kevin
-- Yehuda Katz (ph) 718.877.1325 -------------- next part -------------- An HTML attachment was scrubbed... URL: esdiscuss/attachments/20121118/ab3a80c2/attachment
On Nov 17, 2012, at 7:25 PM, Brendan Eich wrote:
- We could also allow 'let' per (4) in functions not in modules that do not "use strict" but do use new ES6 syntax in their heads, e.g. destructuring parameters, default parameters, rest parameters. Those head features could arguably opt into 'let' syntax but not strict mode.
I'd be worried that it would confusingly break refactored code:
function isPermitted(user) { var permissions = [].slice.call(arguments, 1), let = authorize(permissions); if (!let) { return false; } else return permissions; } // to function isPermitted(user, ...permissions) { var let = authorize(permissions); if (!let) { return false; } else return permissions; }
Yes, this is a downside. I don't favor (5) on this account. New syntax is its own opt-in but using a rest parameter should not opt the whole body into a different piece of new syntax.
Several times, we've discussed whether or not new function definition syntax forms (arrow functions, concise methods, the entire body of a class, generator declarations) should automatically be strict code. These are entirely new ways to write functions and to me feels like a significantly different sort of extension than the parameter variations. However, the current POR is that they are not automatically strict.
Making them always be strict would take care of many more cases where "let" is likely to be used and won't have any backwards compat. issues.
Allen
-------------- next part -------------- An HTML attachment was scrubbed... URL: esdiscuss/attachments/20121118/c63eb4d5/attachment
Yehuda Katz wrote:
Question: does requiring strict mode for changes that break compatibility with ES5 really address the 1JS concerns?
Yes. 1JS is based on ES5 and so includes strict mode.
We're making usages of the identifier let that were valid in ES5 strict invalid in ES6 strict. Doesn't that violate 1JS?
No, you forget that ES5 strict reserves 'let' (and 'yield').
On Nov 18, 2012 4:29 PM, "Brendan Eich" <brendan at mozilla.com> wrote:
Yehuda Katz wrote:
Question: does requiring strict mode for changes that break compatibility with ES5 really address the 1JS concerns?
Yes. 1JS is based on ES5 and so includes strict mode.
I was really asking the below question. I didn't remember that let was reserved and therefore poses no new compatibility issues.
We're making usages of the identifier let that were valid in ES5 strict invalid in ES6 strict. Doesn't that violate 1JS?
No, you forget that ES5 strict reserves 'let' (and 'yield').
Indeed. Thanks for reminding me.
I'm not quite sure how to figure this out from the current draft, but is "let" only available from strict mode code? This is valid under ES5 non-strict via ASI:
So with 1JS in mind, it would seem that "let" would only be a keyword in strict mode.