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
Re: catch vs function scope; var declaration vs initialization
On Mon, May 14, 2012 at 11:57 AM, Claus Reinke claus.rei...@talk21.com 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
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: catch vs function scope; var declaration vs initialization
On Mon, May 14, 2012 at 3:25 AM, T.J. Crowder t...@crowdersoftware.com 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 e...@qfox.nl wrote: On Mon, May 14, 2012 at 11:57 AM, Claus Reinke claus.rei...@talk21.com 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
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: 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
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
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