On 2011-11-11, at 9:21 AM, Erick Lavoie wrote:



Le 11-11-10 23:46 , Bruno Dufour a écrit :
On 2011-11-10, at 7:18 PM, Erick Lavoie wrote:

Running the following code in v8 I get:

0 var f = 0;
1
2 (function ()
3 {
4    try
5    {
6        throw 1;
7    } catch (f)
8    {
9        print(f);  // print 1
10       f = 2;
11       print(f);  // print 2
12   }
13   print(f);      // print 0
14 })();

However, replacing line 11 by

var f = 2;

will print 'undefined' at line 13 instead of '0'. Which means that
although catch introduces a lexical binding for f, a var statement with
the same name inside a catch block introduces a local variable spanning
the whole function. However, the assignation is still made on the
variable local to the catch statement!

I'll look at the standard to understand how this could be explained.

The explanation is simple. A catch introduces a new scope where the identifier of the thrown exception is a mutable binding. So, the assignments to f behave as you observed. However, the spec also states that the outer scope of the catch will be restored as to its original state after the execution of the catch:

"No matter how control leaves the Block the LexicalEnvironment is always restored to its former state." (ES5 spec, p97)

So, in the first case, 0 is printed because is bound to the global, which had the value 0 before the catch. In the second, f is bound to the local var, which was of course undefined before the catch.

Bruno
Right. Still, the surprising thing about this behavior is that the "var f = 2;" statement implicitly refers to two different variables.  The first one is in the function scope and is being created because of the presence of a "var" declaration. The second one is local to the catch block and is the target of all accesses and assignments within this scope. Although this statement can introduce a new variable at the function scope, there is no way to access the created variable in the catch scope.

The var declaration gets floated to the top of the *variable* environment (the function scope in this case), not the lexical environment created for the catch. But, the lexical scope is used first to resolve names, so as you point out, the var isn't accessible at all inside of the catch because it is shadowed by the exception id.


In comparison, a "var f = 2;" statement outside a catch block will refer to a single variable, being both created at the function scope and assigned in the statement.

Well, this difference between variable envs and lexical envs is indeed a little ugly, but isn't it supposed to disappear in ES6 when lexical scoping gets applied across the board?  (I haven't read the new proposal yet...)


Having a single statement with a single identifier refer to two logical variables is somewhat confusing.

Agreed. A 'var x = y' is conceptually a 'var x; x = y;' where the effect of the first part can be seen before the statement itself. But, this is true in other JS constructs as well and somewhat of an orthogonal issue IMHO.

Bruno