Re: Block scoping and redeclarations
On 25 August 2011 18:57, Brendan Eich bren...@mozilla.com wrote: On Aug 25, 2011, at 6:17 AM, Andreas Rossberg wrote: There is no before and after or both here. Hoisting first, with rule 1 enforced; then rule 2 checking. Relative source order of declarations is irrelevant. pedanticWell, only when you're implicitly assuming a somewhat non-standard meaning of across, as rather across or from. Clarifying that amounts to the same thing./pedantic Please don't over-formalize my words here, that would be a big mistake! Hoisting is a very physical metaphor. Hoist that crate! By across I meant across the let declaration in its source position. Not across the let binding which is also hoisted (so I think I see what you mean by across or from -- do I?). Well, in that case you would not capture the order-independence properly. Consider e.g.: { { var x; ... let x} } Neither is the var hoisted across the source position of the let, nor across its scope. Still it's supposed to be an error. I'm not being entirely academic here. It's exactly details like this that crop up when you try to implement (and, presumably, specify) those rules, and they require some ugliness if you want to resolve everything in one pass. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Block scoping and redeclarations
On 24 August 2011 18:03, Brendan Eich bren...@mozilla.com wrote: On Aug 24, 2011, at 2:03 AM, Andreas Rossberg wrote: On 23 August 2011 21:18, Brendan Eich bren...@mozilla.com wrote: I think the rules we have discussed are: 1. Any hoisting of var across let binding the same name (whether explicit, or as in catch blocks and comprehensions, implicit) is an early error. 2. Redeclaration of a name in the same block scope via let, const, or function-in-block is an error. That's it. Shadowing via let, const, and function-in-block is allowed (alpha conversion). That's fine, although for (1) you probably meant hoisting of var across a scope that contains a let binding the same name (or, if you assume that let is hoisted to the beginning of its block already, then you have to be very careful about specifying the exact order in which all the hoisting happens). It doesn't matter whether the hoisting is in the same block, or the var is in a block nested within the let's block (or body) scope. And for (2), you have to specify whether this applies before or after hoisting. In fact, I think it's both, since I assume that we want to make both of these an error: { let x; { var x } } { { let x; var x} } There is no before and after or both here. Hoisting first, with rule 1 enforced; then rule 2 checking. Relative source order of declarations is irrelevant. pedanticWell, only when you're implicitly assuming a somewhat non-standard meaning of across, as rather across or from. Clarifying that amounts to the same thing./pedantic Also, I wouldn't necessarily have regarded catch variables as implicitly let-bound. Seems a bit odd, but I guess it's OK to define it that way if it does the right thing. That is explicit in ES3-in-reality (ES3 was broken), real engines use block scoped catch variable bindings, and those engines that support 'let' (Rhino and SpiderMonkey at least) use exactly the same block-scoping machinery for catch variables as for let bindings. We went over this during ES3.1 and ES4 days, here on-list and in TC39 meetings. No problem reiterating, I realize that was long before your time :-). Sorry for digging up old bones then. :) Not a big deal, I just wasn't aware that you seem to be equating let-bound with block-scoped. That's a bit surprising for the uninitiated. Does it really harm migration? I can see only two scenarios that would end up with an illegal redeclaration: 1) The original function contained a single var x somewhere, and somebody is adding a let x now -- this is no big deal, since it is a new variable anyway and can easily be chosen differently. (And in general, it has to anyway; perhaps better to have a uniform rule of thumb here.) This costs, you are special-pleading. Oh, migrators can absorb *my* preferred tax, for the greater good *I* see. That's not how the game is played. Fair enough. My main point here was that migrators are generally paying that tax anyway, we are just talking about a tax cut for some cases. Anyway, I'll rest my case. I remain somewhat unconvinced that the extra complexity is nil and worthwhile, but there obviously are more critical topics. We'll go ahead and implement the rules that you sketched above. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Block scoping and redeclarations
On Aug 25, 2011, at 6:17 AM, Andreas Rossberg wrote: There is no before and after or both here. Hoisting first, with rule 1 enforced; then rule 2 checking. Relative source order of declarations is irrelevant. pedanticWell, only when you're implicitly assuming a somewhat non-standard meaning of across, as rather across or from. Clarifying that amounts to the same thing./pedantic Please don't over-formalize my words here, that would be a big mistake! Hoisting is a very physical metaphor. Hoist that crate! By across I meant across the let declaration in its source position. Not across the let binding which is also hoisted (so I think I see what you mean by across or from -- do I?). Anyway, I'll rest my case. I remain somewhat unconvinced that the extra complexity is nil and worthwhile, but there obviously are more critical topics. We'll go ahead and implement the rules that you sketched above. Thanks. Given the top-level has to accomodate var and let (for disjoint sets of names), it shouldn't be much more code to do the same in functions (rather than ban mixing of var and let for all names in functions). /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Block scoping and redeclarations
On 23 August 2011 19:14, Allen Wirfs-Brock al...@wirfs-brock.com wrote: On Aug 23, 2011, at 5:31 AM, Andreas Rossberg wrote: We are currently in the process of implementing block scoping for V8 (http://wiki.ecmascript.org/doku.php?id=harmony:block_scoped_bindings). The wiki page spec. is neither complete nor up to date so I wouldn't depend too much on what it says. I'm in the process of writing the actual draft specification for block scoped declaration and expect to have it ready for review in advance of the next TC39 meeting. It's up to you, but it might be more economical to put off your implementation for a couple weeks until that spec. is ready That's OK, we are aware that the spec is not finalized yet. For most part, the semantics is rather obvious, and we try to avoid putting too much work into aspects that aren't clear yet (such as the global scope). Brendan and Dave suggest that certain combinations of `let' and `var' should be an error (more precisely, a syntax error, I assume). However, there are various possibilities to interpret this. Assume that each line in the following is a function scope: { let x; var x } // 1a { var x; let x } // 1b { let x; { var x } } // 2a { var x; { let x } } // 2b { { let x } var x } // 3a { { var x } let x } // 3b { { let x } { var x } } // 4a { { var x } { let x } } // 4b 1a-2a should clearly be errors. Same for 3b arguably, because the var is hoisted to the same scope as the let. In 2b, 3a, and 4a/b, a var is shadowed by a let, which isn't a problem in principle. OTOH, strictly speaking, at least 3a and 4a actually introduce a var-declaration that has already been shadowed by a let-declaration (Dave's words). I think the July meeting discussion covers all of these cases and I agree that 1a,1b, 2a,3b are errors and 2b,3a,4a,4b are not. Hm, I'm not sure I remember that we discussed this particular aspect in detail in July. Sorry if I missed something. I don't think Dave's quote applies to 3a and 4a. The var declaration is always logically hoisted to the top of the function so it is already in place before the let block shadows it. Another way to look at it is that within any scope contour, the same name can not be used within multiple declarations (except for multiple vars for the same name) that occur or are hoisted into that contour. The order of the multiple declaration doesn't really matter. Oh, but that description does not cover Dave's exact example, which actually was { { let x; { var x } } } Here, the var is hoisted across the let's scope, but doesn't end up in the same scope. And we clearly want to rule that out, too. But then, you also want to properly distinguish this case from, say { { { let x } { var x } } } So, while I see what you tried to say there, the fact that it didn't quite nail it reinforces my feeling that any actual rule might be more complicated to specify accurately than worthwhile. * It is a syntax error if a given identifier is declared by both a let-declaration and a var-delaration in the same function. (And similarly, for const vs. var, or function vs. var -- the latter being an incompatible change for the global scope, but it seems like we may abolish that anyway.) I'm not sure that this actually simplifies anything. We still need hoisting rules for let and we still need something like the multiple declaration rules above so just is yet another rule that has to be specified, implemented, and remembered by users. If we think cases such as 3a and 4a are real bug farms then maybe the additional rule carries its weight. But I'm not sure that we have all that much of a hazard even without it. I just don't expect to see much code that looked like 3a or 4a. I'm not sure I follow. It's not an additional rule -- the way I view it it is a rule that replaces a (set of) more complicated rule(s). And if we don't expect the cases in question to show up often, then doesn't that seems rather like an argument for the simplification than against it? That's not to say that I couldn't live with more fine-grained rules, I just don't consider them worthwhile. Ultimately, we want to morally deprecate var for Harmony mode, so introducing too many extra rules around it seems a bit unjustified, unless there is a very good reason. Thanks, /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Block scoping and redeclarations
On 23 August 2011 21:18, Brendan Eich bren...@mozilla.com wrote: I think the rules we have discussed are: 1. Any hoisting of var across let binding the same name (whether explicit, or as in catch blocks and comprehensions, implicit) is an early error. 2. Redeclaration of a name in the same block scope via let, const, or function-in-block is an error. That's it. Shadowing via let, const, and function-in-block is allowed (alpha conversion). That's fine, although for (1) you probably meant hoisting of var across a scope that contains a let binding the same name (or, if you assume that let is hoisted to the beginning of its block already, then you have to be very careful about specifying the exact order in which all the hoisting happens). And for (2), you have to specify whether this applies before or after hoisting. In fact, I think it's both, since I assume that we want to make both of these an error: { let x; { var x } } { { let x; var x} } Also, I wouldn't necessarily have regarded catch variables as implicitly let-bound. Seems a bit odd, but I guess it's OK to define it that way if it does the right thing. Consequently, we propose a very simple rule instead: * It is a syntax error if a given identifier is declared by both a let-declaration and a var-delaration in the same function. (And similarly, for const vs. var, or function vs. var -- the latter being an incompatible change for the global scope, but it seems like we may abolish that anyway.) Anywhere in the same function? This seems unnecessarily restrictive. People will migrate large functions into ES6 and start let-converting while maintaining. We have seen this happen over the last five years in which we've supported let, in Firefox front-end and add-on JS. Does it really harm migration? I can see only two scenarios that would end up with an illegal redeclaration: 1) The original function contained a single var x somewhere, and somebody is adding a let x now -- this is no big deal, since it is a new variable anyway and can easily be chosen differently. (And in general, it has to anyway; perhaps better to have a uniform rule of thumb here.) 2) The original code contained several var x, and somebody starts changing some of them into let incrementally -- attempting this does change the meaning of the code and is extremely likely to break it in subtle ways. It's probably preferable to flag it as an error. * In a similar vein, I think we should probably forbid `var' to coexist with _any_ other form of binding for the same variable in a single function. In particular, for Harmony mode we should rule out the infamous try .. catch(x) { var x = 666; ...}. That is covered by my (1) above, no need for special cases. The catch variable is an implicit let binding. * Finally, do we allow redeclaring functions with let or const, like it used to be the case with var? I propose disallowing it. That's also been a point of recurring TC39 agreement, specifically to future-proof for guards. OK, I'm glad to hear that. :) Thanks, /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Language modes (Was: Block scoping and redeclarations)
That's not to say that I couldn't live with more fine-grained rules, I just don't consider them worthwhile. Ultimately, we want to morally deprecate var for Harmony mode, so introducing too many extra rules around it seems a bit unjustified, unless there is a very good reason. Btw, we had this amusing discussion in July how to name the different language modes without stepping on people's toes. How about classic, strict, and modern? /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Language modes (Was: Block scoping and redeclarations)
On Aug 24, 2011, at 2:08 AM, Andreas Rossberg wrote: Btw, we had this amusing discussion in July how to name the different language modes without stepping on people's toes. How about classic, strict, and modern? The modern mode won't seem very modern twenty years from now. allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Block scoping and redeclarations
On Aug 24, 2011, at 2:03 AM, Andreas Rossberg wrote: On 23 August 2011 21:18, Brendan Eich bren...@mozilla.com wrote: I think the rules we have discussed are: 1. Any hoisting of var across let binding the same name (whether explicit, or as in catch blocks and comprehensions, implicit) is an early error. 2. Redeclaration of a name in the same block scope via let, const, or function-in-block is an error. That's it. Shadowing via let, const, and function-in-block is allowed (alpha conversion). That's fine, although for (1) you probably meant hoisting of var across a scope that contains a let binding the same name (or, if you assume that let is hoisted to the beginning of its block already, then you have to be very careful about specifying the exact order in which all the hoisting happens). It doesn't matter whether the hoisting is in the same block, or the var is in a block nested within the let's block (or body) scope. And for (2), you have to specify whether this applies before or after hoisting. In fact, I think it's both, since I assume that we want to make both of these an error: { let x; { var x } } { { let x; var x} } There is no before and after or both here. Hoisting first, with rule 1 enforced; then rule 2 checking. Relative source order of declarations is irrelevant. Also, I wouldn't necessarily have regarded catch variables as implicitly let-bound. Seems a bit odd, but I guess it's OK to define it that way if it does the right thing. That is explicit in ES3-in-reality (ES3 was broken), real engines use block scoped catch variable bindings, and those engines that support 'let' (Rhino and SpiderMonkey at least) use exactly the same block-scoping machinery for catch variables as for let bindings. We went over this during ES3.1 and ES4 days, here on-list and in TC39 meetings. No problem reiterating, I realize that was long before your time :-). Anywhere in the same function? This seems unnecessarily restrictive. People will migrate large functions into ES6 and start let-converting while maintaining. We have seen this happen over the last five years in which we've supported let, in Firefox front-end and add-on JS. Does it really harm migration? I can see only two scenarios that would end up with an illegal redeclaration: 1) The original function contained a single var x somewhere, and somebody is adding a let x now -- this is no big deal, since it is a new variable anyway and can easily be chosen differently. (And in general, it has to anyway; perhaps better to have a uniform rule of thumb here.) This costs, you are special-pleading. Oh, migrators can absorb *my* preferred tax, for the greater good *I* see. That's not how the game is played. 2) The original code contained several var x, and somebody starts changing some of them into let incrementally -- attempting this does change the meaning of the code and is extremely likely to break it in subtle ways. It's probably preferable to flag it as an error. This is indeed the case. Large functions often use var to redeclare canonical short-named variables (loop controls, this is most common with for loops). A new maintainer free to use 'let' may switch, and find trouble anyway (say they change for (var i ...) to for (let i ...) but i is used after the for loop's end). There are no guarantees, but you are adding a speed-bump. The only upside of the speed-bump is implementor convenience. I do not believe there's any pedagogical gain in practice. I know from our JS1.7+ experience that real code including large functions does mix var and let (_at all_ as you put it -- not for the same name). Implementors have to take one for the orders-larger developer team. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Language modes (Was: Block scoping and redeclarations)
On Wed, Aug 24, 2011 at 11:30 AM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: The modern mode won't seem very modern twenty years from now. allen My understanding is that anything after the Middle Ages is fair game, and I see strict as the middle age between ES.now and ES.future. :-) MIke ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Language modes (Was: Block scoping and redeclarations)
On Aug 24, 2011, at 2:08 AM, Andreas Rossberg wrote: That's not to say that I couldn't live with more fine-grained rules, I just don't consider them worthwhile. Ultimately, we want to morally deprecate var for Harmony mode, so introducing too many extra rules around it seems a bit unjustified, unless there is a very good reason. Btw, we had this amusing discussion in July how to name the different language modes without stepping on people's toes. How about classic, strict, and modern? I once made the mistake of using _NEW as a name part for an opcode in SpiderMonkey. Got old fast. We want few modes, ideally only RFC4329 version numbers on one line, not a lattice. This is why Harmony is based on ES5 strict and we do not want an ES6 stricter strict (use really strict). The argument in July, which I was lucky enough to (mostly) miss, seemed spec jargon bikeshedding. Extended mode vs. something else. But note that extended is timeless, and if we avoid refracting modes through one another, and keep to a linear regime, the spec does not need to distinguish ES6 extended from ES7. The spec version itself does that, and (modulo more convenient forms for HTML authors) the 6 in script type=application/javascript;version=6 means the same thing. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Block scoping and redeclarations
On Aug 24, 2011, at 2:01 AM, Andreas Rossberg wrote: On 23 August 2011 19:14, Allen Wirfs-Brock al...@wirfs-brock.com wrote: Oh, but that description does not cover Dave's exact example, which actually was { { let x; { var x } } } Here, the var is hoisted across the let's scope, but doesn't end up in the same scope. And we clearly want to rule that out, too. But then, you also want to properly distinguish this case from, say This is essentially the same as the hosting a var out of a catch clause where the var and catch parameter have the same name. I tried to get that defined as an error for ES5 and it didn't fly because of backwards compat. concerns. I suspect we would come to the same conclusion this time. But, there is nothing stoping an implementation from issuing a warning for such occurrences. It might even be a good idea. We might be able to even get agreement to include in the spec. a non-normative recommendation to that regard similarly to what ES5 has regarding function declarations within blocks. Allen___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Block scoping and redeclarations
On Aug 24, 2011, at 9:43 AM, Allen Wirfs-Brock wrote: On Aug 24, 2011, at 2:01 AM, Andreas Rossberg wrote: On 23 August 2011 19:14, Allen Wirfs-Brock al...@wirfs-brock.com wrote: Oh, but that description does not cover Dave's exact example, which actually was { { let x; { var x } } } Here, the var is hoisted across the let's scope, but doesn't end up in the same scope. And we clearly want to rule that out, too. But then, you also want to properly distinguish this case from, say This is essentially the same as the hosting a var out of a catch clause where the var and catch parameter have the same name. I tried to get that defined as an error for ES5 and it didn't fly because of backwards compat. concerns. I suspect we would come to the same conclusion this time. Wasn't the concern theoretical? We have more time now to shake the trees. If we find web content with ... catch (e) {... var e...} then we should think hard (my migration tax argument cuts all ways). But I've never seen any such code. Indeed try/catch is rare, mostly used to ignore deep-throw exceptions at or near a top level (event loop). But, there is nothing stoping an implementation from issuing a warning for such occurrences. It might even be a good idea. We might be able to even get agreement to include in the spec. a non-normative recommendation to that regard similarly to what ES5 has regarding function declarations within blocks. Warnings are mostly fruitless, in my experience. Mostly meaning not that they sometimes work (they may, I just don't know), rather that sometimes they just bug the heck out of developers and cause a backlash (this happened with SpiderMonkey's strict-option warning against 'with', long before ES5 strict), or merely degrade the coin of the console.log realm. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Block scoping and redeclarations
On Aug 24, 2011, at 10:28 AM, Brendan Eich wrote: On Aug 24, 2011, at 9:43 AM, Allen Wirfs-Brock wrote: This is essentially the same as the hosting a var out of a catch clause where the var and catch parameter have the same name. I tried to get that defined as an error for ES5 and it didn't fly because of backwards compat. concerns. I suspect we would come to the same conclusion this time. Wasn't the concern theoretical? Allen reminded me that the case he wanted to change for ES3.1 was with (obj) var prop = 42; which insanely binds prop in the enclosing function or global object, but then may or may not set obj.prop and leave the prop variable undefined. Nuts, but hoisting is consistent, and I (among others on TC39) did not think ES3.1 should make a breaking change here. Not just because this might be in web content (it's more likely that ... catch (e) { var e... }), but because we weren't supposed to be making breaking changes in ES3.1. Anyway, Harmony is opt-in, and based on ES5 strict so 'with' is *gone*, so only the catch (e) { var e... } conflict remains to make an error. Again I believe we can get away with this change. It will be an early error, and the pattern (unlike free-floating and repeated var usage in big functions) is exceedingly rare -- never seen by me in the wild. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Block scoping and redeclarations
We are currently in the process of implementing block scoping for V8 (http://wiki.ecmascript.org/doku.php?id=harmony:block_scoped_bindings). Brendan and Dave suggest that certain combinations of `let' and `var' should be an error (more precisely, a syntax error, I assume). However, there are various possibilities to interpret this. Assume that each line in the following is a function scope: { let x; var x } // 1a { var x; let x } // 1b { let x; { var x } } // 2a { var x; { let x } } // 2b { { let x } var x }// 3a { { var x } let x }// 3b { { let x } { var x } } // 4a { { var x } { let x } } // 4b 1a-2a should clearly be errors. Same for 3b arguably, because the var is hoisted to the same scope as the let. In 2b, 3a, and 4a/b, a var is shadowed by a let, which isn't a problem in principle. OTOH, strictly speaking, at least 3a and 4a actually introduce a var-declaration that has already been shadowed by a let-declaration (Dave's words). There are lots of arguments that can be made here, but ultimately, my feeling is that any rule that allows some of the examples above, but not others is both brittle and confusing, and potentially too complicated to memoize correctly for the average programmer. Consequently, we propose a very simple rule instead: * It is a syntax error if a given identifier is declared by both a let-declaration and a var-delaration in the same function. (And similarly, for const vs. var, or function vs. var -- the latter being an incompatible change for the global scope, but it seems like we may abolish that anyway.) We could go even further with the first point: we could make it a syntax error to mix var and let _at all_ in a single function, regardless of what identifiers they declare. I would be perfectly fine with that, too, but expect that others would disagree. * In a similar vein, I think we should probably forbid `var' to coexist with _any_ other form of binding for the same variable in a single function. In particular, for Harmony mode we should rule out the infamous try .. catch(x) { var x = 666; ...}. * Finally, do we allow redeclaring functions with let or const, like it used to be the case with var? I propose disallowing it. What do you think? Thanks, /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Block scoping and redeclarations
I'm in favor of letting let shadow var, but having a var declaration within a let's scope be a error. I see this as being the most compatible when working in global scope (and concatenating files). I suspect that most new code will quickly move to using let everwhere. On Tue, Aug 23, 2011 at 5:31 AM, Andreas Rossberg rossb...@google.comwrote: We are currently in the process of implementing block scoping for V8 (http://wiki.ecmascript.org/doku.php?id=harmony:block_scoped_bindings). Brendan and Dave suggest that certain combinations of `let' and `var' should be an error (more precisely, a syntax error, I assume). However, there are various possibilities to interpret this. Assume that each line in the following is a function scope: { let x; var x } // 1a { var x; let x } // 1b { let x; { var x } } // 2a { var x; { let x } } // 2b { { let x } var x }// 3a { { var x } let x }// 3b { { let x } { var x } } // 4a { { var x } { let x } } // 4b 1a-2a should clearly be errors. Same for 3b arguably, because the var is hoisted to the same scope as the let. In 2b, 3a, and 4a/b, a var is shadowed by a let, which isn't a problem in principle. OTOH, strictly speaking, at least 3a and 4a actually introduce a var-declaration that has already been shadowed by a let-declaration (Dave's words). There are lots of arguments that can be made here, but ultimately, my feeling is that any rule that allows some of the examples above, but not others is both brittle and confusing, and potentially too complicated to memoize correctly for the average programmer. Consequently, we propose a very simple rule instead: * It is a syntax error if a given identifier is declared by both a let-declaration and a var-delaration in the same function. (And similarly, for const vs. var, or function vs. var -- the latter being an incompatible change for the global scope, but it seems like we may abolish that anyway.) We could go even further with the first point: we could make it a syntax error to mix var and let _at all_ in a single function, regardless of what identifiers they declare. I would be perfectly fine with that, too, but expect that others would disagree. * In a similar vein, I think we should probably forbid `var' to coexist with _any_ other form of binding for the same variable in a single function. In particular, for Harmony mode we should rule out the infamous try .. catch(x) { var x = 666; ...}. * Finally, do we allow redeclaring functions with let or const, like it used to be the case with var? I propose disallowing it. What do you think? Thanks, /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Block scoping and redeclarations
On Aug 23, 2011, at 5:31 AM, Andreas Rossberg wrote: We are currently in the process of implementing block scoping for V8 (http://wiki.ecmascript.org/doku.php?id=harmony:block_scoped_bindings). The wiki page spec. is neither complete nor up to date so I wouldn't depend too much on what it says. I'm in the process of writing the actual draft specification for block scoped declaration and expect to have it ready for review in advance of the next TC39 meeting. It's up to you, but it might be more economical to put off your implementation for a couple weeks until that spec. is ready Brendan and Dave suggest that certain combinations of `let' and `var' should be an error (more precisely, a syntax error, I assume). However, there are various possibilities to interpret this. Assume that each line in the following is a function scope: { let x; var x } // 1a { var x; let x } // 1b { let x; { var x } } // 2a { var x; { let x } } // 2b { { let x } var x }// 3a { { var x } let x }// 3b { { let x } { var x } } // 4a { { var x } { let x } } // 4b 1a-2a should clearly be errors. Same for 3b arguably, because the var is hoisted to the same scope as the let. In 2b, 3a, and 4a/b, a var is shadowed by a let, which isn't a problem in principle. OTOH, strictly speaking, at least 3a and 4a actually introduce a var-declaration that has already been shadowed by a let-declaration (Dave's words). I think the July meeting discussion covers all of these cases and I agree that 1a,1b, 2a,3b are errors and 2b,3a,4a,4b are not. I don't think Dave's quote applies to 3a and 4a. The var declaration is always logically hoisted to the top of the function so it is already in place before the let block shadows it. Another way to look at it is that within any scope contour, the same name can not be used within multiple declarations (except for multiple vars for the same name) that occur or are hoisted into that contour. The order of the multiple declaration doesn't really matter. There are lots of arguments that can be made here, but ultimately, my feeling is that any rule that allows some of the examples above, but not others is both brittle and confusing, and potentially too complicated to memoize correctly for the average programmer. Consequently, we propose a very simple rule instead: I think the rule I stated above is fairly simple. The only complication relates to var which has to get special treatment regardless. * It is a syntax error if a given identifier is declared by both a let-declaration and a var-delaration in the same function. (And similarly, for const vs. var, or function vs. var -- the latter being an incompatible change for the global scope, but it seems like we may abolish that anyway.) I'm not sure that this actually simplifies anything. We still need hoisting rules for let and we still need something like the multiple declaration rules above so just is yet another rule that has to be specified, implemented, and remembered by users. If we think cases such as 3a and 4a are real bug farms then maybe the additional rule carries its weight. But I'm not sure that we have all that much of a hazard even without it. I just don't expect to see much code that looked like 3a or 4a. We could go even further with the first point: we could make it a syntax error to mix var and let _at all_ in a single function, regardless of what identifiers they declare. I would be perfectly fine with that, too, but expect that others would disagree. It would probably impede migration to Harmony mode. * In a similar vein, I think we should probably forbid `var' to coexist with _any_ other form of binding for the same variable in a single function. In particular, for Harmony mode we should rule out the infamous try .. catch(x) { var x = 666; ...}. Also a potential migration problem. (If it doesn't actually occur on the web it isn't really an issue. If it does, then forbidding it impedes migration) * Finally, do we allow redeclaring functions with let or const, like it used to be the case with var? I propose disallowing it. I agree, at least within function bodies. I think their may be different considerations for the global scope. Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Block scoping and redeclarations
On Aug 23, 2011, at 5:31 AM, Andreas Rossberg wrote: However, there are various possibilities to interpret this. Assume that each line in the following is a function scope: { let x; var x } // 1a { var x; let x } // 1b { let x; { var x } } // 2a { var x; { let x } } // 2b { { let x } var x }// 3a { { var x } let x }// 3b { { let x } { var x } } // 4a { { var x } { let x } } // 4b As var hoists to function scope, the order doesn't matter, so what Allen said: 1[ab], 2a, 3b all should fail with early error (yeah, SyntaxError -- what else? :-P), while 2b, 3a, and 4[ab] all succeed. There are lots of arguments that can be made here, but ultimately, my feeling is that any rule that allows some of the examples above, but not others is both brittle and confusing, and potentially too complicated to memoize correctly for the average programmer. I think the rules we have discussed are: 1. Any hoisting of var across let binding the same name (whether explicit, or as in catch blocks and comprehensions, implicit) is an early error. 2. Redeclaration of a name in the same block scope via let, const, or function-in-block is an error. That's it. Shadowing via let, const, and function-in-block is allowed (alpha conversion). Consequently, we propose a very simple rule instead: * It is a syntax error if a given identifier is declared by both a let-declaration and a var-delaration in the same function. (And similarly, for const vs. var, or function vs. var -- the latter being an incompatible change for the global scope, but it seems like we may abolish that anyway.) Anywhere in the same function? This seems unnecessarily restrictive. People will migrate large functions into ES6 and start let-converting while maintaining. We have seen this happen over the last five years in which we've supported let, in Firefox front-end and add-on JS. We could go even further with the first point: we could make it a syntax error to mix var and let _at all_ in a single function, regardless of what identifiers they declare. I would be perfectly fine with that, too, but expect that others would disagree. You got that right ;-). * In a similar vein, I think we should probably forbid `var' to coexist with _any_ other form of binding for the same variable in a single function. In particular, for Harmony mode we should rule out the infamous try .. catch(x) { var x = 666; ...}. That is covered by my (1) above, no need for special cases. The catch variable is an implicit let binding. * Finally, do we allow redeclaring functions with let or const, like it used to be the case with var? I propose disallowing it. That's also been a point of recurring TC39 agreement, specifically to future-proof for guards. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss