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