Re: catch vs function scope; var declaration vs initialization
Claus Reinke wrote: firefox 12 complains: 'e is not defined' Thanks for pointing this out. It is a fairly recent regression. I used `hg bisect` to find it and filed https://bugzilla.mozilla.org/show_bug.cgi?id=755099 I agree with Allen, we should clear this dark corner of the deck with vigorous application of early-error solution and scrub in nightly builds to prove no real code relies on var e; inside catch (e) {...} hoisting. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: catch vs function scope; var declaration vs initialization
On May 14, 2012, at 2:44 PM, Claus Reinke wrote: > >> Because let is a new feature, this restriction doesn't introduce any >> backwards compatibility issues. However, for consistency, the draft >> also currently applies the same let declaration restrictions to catch >> parameters. > > Even better!-) And in line with treating catch as an anonymous function. An analogy with inner functions isn't needed and wouldn't be correct. This is simply appling the static semantics of Block level declarations. A Block is not allowed to var declare (including via nested blocks) any identifier that is lexically declared in the block (but not including nested blocks). function f() { try { throw "hi" } catch (e) { var v; }; } is legal and binds "v" at the top-level of function f. If the catch clause was treated like an anonymous function, "v" would be bound at the level of the catch clause. It isn't... In terms of scope contours the above is equivalent to function f() { { //throw "hi" } { let e; var v; } } Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: catch vs function scope; var declaration vs initialization
undefined undefined hu is what should be produced according to the spec. Divergence among implementations is a good sign that there is an opportunity to clean up this particular mess. Yes, please!-) The current ES6 draft requires an early error for this function because it is trying to hoist a var declaration across a block-level declaration of the same identifier. EG, 'let' vs 'var' would have been my next question. Good to know that this particular issue does not propagate to 'let'! Because let is a new feature, this restriction doesn't introduce any backwards compatibility issues. However, for consistency, the draft also currently applies the same let declaration restrictions to catch parameters. Even better!-) And in line with treating catch as an anonymous function. Claus Your experiment suggests that that we might actually be able to to that ... Allen On May 14, 2012, at 2:57 AM, Claus Reinke wrote: What should be the output of the following code? (function(){ try { throw "hi"; } catch (e) { var e = "ho"; var o = "hu"; var u; console.log(e); } console.log(e,u,o); }()); It seems clear that the first console.log should output 'ho'. Implementations seem to disagree on the second console.log, though. From my current understanding of the spec, I expected: undefined undefined 'hu' which I consider unfortunate; especially the first 'undefined' was intended to demonstrate the bad effects of separating declaration from initialization while treating catch and function differently, in terms of scoping. node, opera: undefined undefined 'hu' firefox 12 complains: 'e is not defined' ie 9 outputs: houndefinedhu It looks as if firefox misses the hoisted declaration of 'e' (it doesn't complain about 'u', only about 'e') while ie9 somehow merges the declaration and the catch parameter. Claus ___ 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: catch vs function scope; var declaration vs initialization
Inside the catch, the catch-scope is first for reading and writing. In "practice" (as in: what implementations permit; not: what is used), there is also this variation: try { throw "oops" } catch (f) { function f() { console.log(f) } console.log(f) } console.log(f) This isn't permitted in ES5, and 'f' would be block-scoped if permitted in ES6. In common non-standard extensions to ES5, the function and references to 'f' in its body are bound outside the catch. I don't even want to look at what happens with a function declaration in a catch where the body references the catch parameter.. I'm currently looking at these edge cases for implementing renaming (program transformation) - no fun. §10.5 tells us that `var` creates bindings in the anonymous function's environment, so the function's env has `e`, `o`, and `u` bindings. §12.14 tells us that within the `catch`, a new environment is created with the function's environment being the parent. So the assignment to `e` is to the `catch`'s `e`, not the function's. Which means that the single occurrence of 'e' in 'var e = "ho"' is bound to two different scopes: outside the catch for creating a binding, in the catch for assignment. As Allen anticipated, I was wondering about the effects on mixing 'let' and 'var', too. Claus ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Concise Function Body
On May 14, 2012, at 9:53 AM, Brendan Eich wrote: > From where is this produced? It's unsound if from MemberExpression (ES1-5) or > PrimaryExpression (ES6) -> FunctionExpression -> ... ConciseBody. AssignmentExpression : ... ArrowFunction ArrowFunction : ArrowParameter => ConciseBody > > /be > > Erik Arvidsson wrote: >> The latest ES6 draft introduced the notion of a concise function body >> and it is being used for arrow functions as well as for methods and >> set/get accessors. >> >> Grammar: >> >> ConciseBody : >> [lookahead does not include { ] AssignmentExpression >> { FunctionBody } >> >> Example: >> >> var object = { >> get x() this._x, >> set x(v) this._x = v, >> method() this._x >> }; >> >> I don't remember us ever discussing this change? >> >> Personally I think it makes things more consistent since concise >> function bodies are allowed in ArrowFunction but I've heard people >> complain about it already. >> >> p.s. Allen, the spec draft has a bunch of ConsiseBody typos. >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Concise Function Body
I'm pretty sure there was some discussion about this on some thread, but it may have been fleeting... Concise methods (http://wiki.ecmascript.org/doku.php?id=harmony:concise_object_literal_extensions#methods ) have been proposals for quite some time. When I added ArrowFunctions into the draft, it seemed to make sense to consistently apply them to the other new function definition form (concise methods) that we already had added. Once that was done, it also made sense, from a consistency standpoint, to permit them for get/set properties. This means there is a simple rule: function definition using the keyword function always have a bracketed body. All other forms of function definition use ConciseBody which allows for either an assignment expression or a bracketed body. I'm happy to debate this if there is any disagreement, that's why we have spec. drafts. Nothing is set in stone. Allen On May 14, 2012, at 9:31 AM, Erik Arvidsson wrote: > The latest ES6 draft introduced the notion of a concise function body > and it is being used for arrow functions as well as for methods and > set/get accessors. > > Grammar: > > ConciseBody : > [lookahead does not include { ] AssignmentExpression > { FunctionBody } > > Example: > > var object = { > get x() this._x, > set x(v) this._x = v, > method() this._x > }; > > I don't remember us ever discussing this change? > > Personally I think it makes things more consistent since concise > function bodies are allowed in ArrowFunction but I've heard people > complain about it already. > > p.s. Allen, the spec draft has a bunch of ConsiseBody typos. all fixed... > > -- > erik > ___ > 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: Concise Function Body
From where is this produced? It's unsound if from MemberExpression (ES1-5) or PrimaryExpression (ES6) -> FunctionExpression -> ... ConciseBody. /be Erik Arvidsson wrote: The latest ES6 draft introduced the notion of a concise function body and it is being used for arrow functions as well as for methods and set/get accessors. Grammar: ConciseBody : [lookahead does not include { ] AssignmentExpression { FunctionBody } Example: var object = { get x() this._x, set x(v) this._x = v, method() this._x }; I don't remember us ever discussing this change? Personally I think it makes things more consistent since concise function bodies are allowed in ArrowFunction but I've heard people complain about it already. p.s. Allen, the spec draft has a bunch of ConsiseBody typos. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Concise Function Body
The latest ES6 draft introduced the notion of a concise function body and it is being used for arrow functions as well as for methods and set/get accessors. Grammar: ConciseBody : [lookahead does not include { ] AssignmentExpression { FunctionBody } Example: var object = { get x() this._x, set x(v) this._x = v, method() this._x }; I don't remember us ever discussing this change? Personally I think it makes things more consistent since concise function bodies are allowed in ArrowFunction but I've heard people complain about it already. p.s. Allen, the spec draft has a bunch of ConsiseBody typos. -- erik ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: catch vs function scope; var declaration vs initialization
On Mon, May 14, 2012 at 3:25 AM, T.J. Crowder wrote: >> Inside the catch, the catch-scope is first for reading and writing. >> But the catch scopes are ignored for declaring new variables. So your >> expectation seems to be the correct one. > > > That was my analysis as well. > > §10.5 tells us that `var` creates bindings in the anonymous function's > environment, so the function's env has `e`, `o`, and `u` bindings. > > §12.14 tells us that within the `catch`, a new environment is created with > the function's environment being the parent. So the assignment to `e` is to > the `catch`'s `e`, not the function's. > > Annotating that code a bit: > > (function(){ > var e; // Where these actually happen > var o; > var u; > > try { > throw "hi"; > } catch (e) { > e = "ho"; // Assigns to the `catch` env's `e` > o = "hu"; // Assigns to the function's `o` > console.log(e); > } > console.log(e, u, o); // Expect undefined undefined "hu" I believe that -- if we had any practical way to measure this -- 'most' web developers would expect 'ho undefined hu'. This is the sensible output, the one given by ie9. It is sensible because the simple synopsis of the funky var rules is "variables get values when assignments are executed". In my opinion the spec-ed answer here is less useful to developers than the ie9 answer. It may be true that specifications which allowed the sensible answer would result in other more serious nonsense of course. jjb > > }()); > > -- T.J. > > > On 14 May 2012 11:11, Peter van der Zee wrote: >> >> On Mon, May 14, 2012 at 11:57 AM, Claus Reinke >> wrote: >> > What should be the output of the following code? >> > >> > (function(){ >> > >> > try { >> > throw "hi"; >> > } catch (e) { >> > var e = "ho"; >> > var o = "hu"; >> > var u; >> > console.log(e); >> > } >> > console.log(e,u,o); >> > >> > }()); >> > >> > It seems clear that the first console.log should output 'ho'. >> > Implementations seem to disagree on the second console.log, though. >> > >> > From my current understanding of the spec, I expected: >> > undefined undefined 'hu' >> > >> >> Inside the catch, the catch-scope is first for reading and writing. >> But the catch scopes are ignored for declaring new variables. So your >> expectation seems to be the correct one. `e` is created in the scope >> of the anonymous function. Likewise, `o` and `u` are created in that >> scope too (so neither throw at the second console.log). "ho" is >> assigned to the catch-scope `e`, since that's the first scope in the >> scope traversal lookup at that point. Catch scopes are weird, yo. >> >> - peter >> ___ >> 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 > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: catch vs function scope; var declaration vs initialization
undefined undefined hu is what should be produced according to the spec. Divergence among implementations is a good sign that there is an opportunity to clean up this particular mess. The current ES6 draft requires an early error for this function because it is trying to hoist a var declaration across a block-level declaration of the same identifier. EG, function f() { { let x=1; //early error let declaration of x in a block that contains a nested var declaration of x { var x=2; } } } Because let is a new feature, this restriction doesn't introduce any backwards compatibility issues. However, for consistency, the draft also currently applies the same let declaration restrictions to catch parameters. Your experiment suggests that that we might actually be able to to that ... Allen On May 14, 2012, at 2:57 AM, Claus Reinke wrote: > What should be the output of the following code? > > (function(){ > > try { > throw "hi"; > } catch (e) { > var e = "ho"; > var o = "hu"; > var u; > console.log(e); > } > console.log(e,u,o); > > }()); > > It seems clear that the first console.log should output 'ho'. > Implementations seem to disagree on the second console.log, though. > > From my current understanding of the spec, I expected: > undefined undefined 'hu' > > which I consider unfortunate; especially the first 'undefined' > was intended to demonstrate the bad effects of separating declaration from > initialization while treating catch and function differently, in terms of > scoping. > > node, opera: undefined undefined 'hu' > > firefox 12 complains: 'e is not defined' > > ie 9 outputs: houndefinedhu > > It looks as if firefox misses the hoisted declaration of 'e' > (it doesn't complain about 'u', only about 'e') while ie9 somehow merges the > declaration and the catch parameter. > > Claus > ___ > 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: Reflect.parse (from RE:typeof null)
it appears that the SpiderMonkey AST has emerged as a de-facto standard. Really? I guess there are many more users of Uglify and Esprima is growing fast. Personally I never heard of any non-Mozilla uses of the SpiderMonkey API, but perhaps you can point to some. I was merely stating my personal impression. It is difficult to pin down all the bits of information that contributed to that impression, but here are some of them: - not all JS parsers document their AST, but it appears that the SpiderMonkey AST has the largest number of (partial) implementations; most parsers have their own AST (jslint and jshint might share their AST by forking) but SpiderMonkey, esprima, PanPG, reflect.js, jstr all refer to the same AST document. Of those, esprima seems the most active. The combination of Reflect.parse awareness and esprima being an efficient cross- browser implementation is certainly the reason why I think that this AST spec is in the process of winning. - even though I've moved to JS relatively recently, I've already worked with 3 different JS parsers and have written one myself; it just isn't funny anymore: all of them had different ASTs and varying support, and I was still missing out on one popular JS parser and its community; so I'm in the process of consolidating my JS tool efforts on top of esprima, giving up or porting my own code to gain from collaboration; - some of the people working with or on esprima have been working with other JS parsers before, so I assume they, too, prefer convergence and sharing over their previous efforts; I expect more tools to be converted for use with esprima; esprima doesn't try to be anything but an efficient, simple, ES parser. It doesn't define its own AST, special-purpose code has been moved out of the main branch, so it just aims to be a common building block for tool builders. Having different standards compete in the market has its advantages, but not for the foundations on which tool-builders base and share their work. Code implementing the ES grammar is such a foundation. There isn't much added value to be expected from parsing JS differently, we just need one good parser, one useable AST format. Depending on half a dozen parsers with slightly different ASTs, just because each was popular at a time when a different JS tool project was started, is slowing down progress, and adds to complexity and maintenance costs. Since I used to be among those asking for an ES standard AST, I just wanted to join this thread by pointing out that de-facto standardizing on esprima (or on the Reflect.parse AST it uses) appears to offer a pragmatic solution to this problem. For my own tool building purposes, that is sufficient for the moment. It would be good if the ES test suite included parser-only tests, though, so that one could test JS frontends that do not have a JS engine behind them for conformance to the ES spec grammar. Also: I think this might be a better topic for the js-tools http://groups.google.com/group/js-tools?pli=1 As you know, that was one motivation for starting that group. Claus ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: catch vs function scope; var declaration vs initialization
> > Inside the catch, the catch-scope is first for reading and writing. > But the catch scopes are ignored for declaring new variables. So your > expectation seems to be the correct one. That was my analysis as well. §10.5 tells us that `var` creates bindings in the anonymous function's environment, so the function's env has `e`, `o`, and `u` bindings. §12.14 tells us that within the `catch`, a new environment is created with the function's environment being the parent. So the assignment to `e` is to the `catch`'s `e`, not the function's. Annotating that code a bit: (function(){ var e; // Where these actually happen var o; var u; try { throw "hi"; } catch (e) { e = "ho"; // Assigns to the `catch` env's `e` o = "hu"; // Assigns to the function's `o` console.log(e); } console.log(e, u, o); // Expect undefined undefined "hu" }()); -- T.J. On 14 May 2012 11:11, Peter van der Zee wrote: > On Mon, May 14, 2012 at 11:57 AM, Claus Reinke > wrote: > > What should be the output of the following code? > > > > (function(){ > > > > try { > > throw "hi"; > > } catch (e) { > > var e = "ho"; > > var o = "hu"; > > var u; > > console.log(e); > > } > > console.log(e,u,o); > > > > }()); > > > > It seems clear that the first console.log should output 'ho'. > > Implementations seem to disagree on the second console.log, though. > > > > From my current understanding of the spec, I expected: > > undefined undefined 'hu' > > > > Inside the catch, the catch-scope is first for reading and writing. > But the catch scopes are ignored for declaring new variables. So your > expectation seems to be the correct one. `e` is created in the scope > of the anonymous function. Likewise, `o` and `u` are created in that > scope too (so neither throw at the second console.log). "ho" is > assigned to the catch-scope `e`, since that's the first scope in the > scope traversal lookup at that point. Catch scopes are weird, yo. > > - peter > ___ > 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: catch vs function scope; var declaration vs initialization
On Mon, May 14, 2012 at 11:57 AM, Claus Reinke wrote: > What should be the output of the following code? > > (function(){ > > try { > throw "hi"; > } catch (e) { > var e = "ho"; > var o = "hu"; > var u; > console.log(e); > } > console.log(e,u,o); > > }()); > > It seems clear that the first console.log should output 'ho'. > Implementations seem to disagree on the second console.log, though. > > From my current understanding of the spec, I expected: > undefined undefined 'hu' > Inside the catch, the catch-scope is first for reading and writing. But the catch scopes are ignored for declaring new variables. So your expectation seems to be the correct one. `e` is created in the scope of the anonymous function. Likewise, `o` and `u` are created in that scope too (so neither throw at the second console.log). "ho" is assigned to the catch-scope `e`, since that's the first scope in the scope traversal lookup at that point. Catch scopes are weird, yo. - peter ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
catch vs function scope; var declaration vs initialization
What should be the output of the following code? (function(){ try { throw "hi"; } catch (e) { var e = "ho"; var o = "hu"; var u; console.log(e); } console.log(e,u,o); }()); It seems clear that the first console.log should output 'ho'. Implementations seem to disagree on the second console.log, though. From my current understanding of the spec, I expected: undefined undefined 'hu' which I consider unfortunate; especially the first 'undefined' was intended to demonstrate the bad effects of separating declaration from initialization while treating catch and function differently, in terms of scoping. node, opera: undefined undefined 'hu' firefox 12 complains: 'e is not defined' ie 9 outputs: houndefinedhu It looks as if firefox misses the hoisted declaration of 'e' (it doesn't complain about 'u', only about 'e') while ie9 somehow merges the declaration and the catch parameter. Claus ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss