On May 9, 2012, at 11:25 AM, Andreas Rossberg wrote:

> On 9 May 2012 19:06, Allen Wirfs-Brock <[email protected]> wrote:
>> On May 9, 2012, at 8:30 AM, Andreas Rossberg wrote:
>>> I still don't quite understand the semantics of a single toplevel
>>> environment (STL) for multiple programs (as opposed to the nesting
>>> approach). As far as I can see, because static checking of separate
>>> programs is interleaved with their execution, using a single
>>> environment would require making lexical environments extensible, i.e.
>>> mutable, which is something that does not go well with lexical
>>> scoping.
>> 
>> Yes, the STL level needs to be extensible.  This is also need for non-strict
>> eval at the top level which can add declarations to the TL.
> 
> True. Which is quite unfortunate. Before 1JS I would have argued: so
> what, non-strict mode isn't lexically scoped anyway. But now it means
> that no code can be fully lexically scoped.
> 
> And by that I don't just mean that bindings can disappear from the
> global object at the top of the scope chain. That's not great either,
> but at least leads to failure.
> 
> But extensible scopes harm lexical scoping in more serious ways: they
> can lead to variable references *changing* between static and dynamic
> (see below). That is truly bad.
> 
> 
>> But I would argue that that violates lexical
>> scoping: x is not bound in the lexical scope in which f was checked
>> and compiled. If its inner eval sees additional (declarative)
>> bindings, then scoping is something else -- especially, when new
>> bindings can also introduce shadowing. Consider:
>> 
>> <script>
>> var x = 7;
>> function f() { return [x, eval("x")]; }
>> </script>
>> 
>> <script>
>> let x = 9;
>> alert(f());
>> </script>
>> 
>> Early error loading the second script!  At global or function scope the same
>> identifier can't be declared using both let and var.
> 
> Sorry, yes, that was a stupid example. What I should have written is
> something like:
> 
> <script>
> Object.getPrototypeOf(this).x = 7;
> </script>
> 
> <script>
> function f() { return [x, eval("x")]; }
> </script>
> 
> <script>
> let x = 9;
> alert(f());
> </script>
> 
> Here, the reference to x in the second script is statically
> resolvable, and it should give 7, shouldn't it? How would a STL
> semantics deal with that?


Key point: all global var/function declarations use properties of the GO as 
their backing store.  But not all properties of the GO correspond to 
var/function bindings. We can know which GO properties correspond to actual ES 
declarations and can apply rules accordingly. This is what ES5.1 (corrected by 
the fix for bug 78) already does.  ES6 can do better by recognizing that we 
aren't limited to the GO property attributes to manage global declarations.

The reference within the function in the second script, at best resolves to a 
GO property that does not correspond to a declared ES binding.  There is no 
guarantee that the GO property (it's configurable) will exist when the function 
is evaluated.  What an early static binding phase of processing script 2 should 
do is try to statically resolve the reference to x.  When it gets to the global 
environment it sees that the currently is only a dynamic property binding so it 
should decide that x can not be statically bound.

The ES5.1 rule that applies to the above example, is that inherited properties  
of the GO are not considered to be a pre-existing declarations.  So variable 
instantiation for x in the 2nd script (in ES5.1 it would have to be a var 
instead of a let, but the same principal applies)  will create a new 
binding/own property on the GO.  This shadows (rather than overwrites) the x 
property that would have been  inherited from the GO's prototype.

> 
> 
>>> It would be quite surprising if this returned [7, 9]. In particular,
>>> it would violate one important expectation I have about eval, namely
>>> that an expression E that evaluates successfully always is equivalent
>>> to eval("E").
>> 

Agreed, it should return [9, 9]




>> Does happen with STL. But something like it would happen with  per Program
>> nested top levels.
>> 
>> <script>
>> var x = 7;
>> function f() { return [x, (0,eval)("x")]; }  //indirect eval
>> </script>
>> 
>> <script>
>> let x = 9;
>> alert(f());
>> </script>
>> 
>> Produces [7,9]??  Indirect eval presumably uses the current top level as it
>> doesn't have any context to choose any other.
> 
> Yes, but indirect eval is a different story altogether. It doesn't use
> the (call site's) lexical scope. Direct eval (aka the eval operator)
> does. So clearly, with indirect eval you wouldn't expect any such
> equivalence.

I would expect a variable reference that resolve to a global environment 
binding  to product the same result whether or not the reference was inline, in 
a direct eval, or in an indirect eval.

Allen

_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to