block scope + direct non-strict eval

Allen Wirfs-Brock allen at wirfs-brock.com
Tue Jan 31 10:39:41 PST 2012


On Jan 31, 2012, at 10:22 AM, Brendan Eich wrote:

>> Allen Wirfs-Brock <mailto:allen at wirfs-brock.com>
>> January 31, 2012 9:20 AM
>> 
>> But it's an issue that I'ver been thinking about since the last meeting.
>> 
>> The basic difference between non-strict direct eval and strict direct eval is that strict creates a new nested environment contour that is used as both the VariableEnvironement and LexicalEnvironment while non-strict uses the currently active Variable/Lexical environment.
>> 
>> It there are two possible semantics for non-strict eval with lexical declaration that I have come up with are:
>> 1) same as ES5, it currents it uses/extends the current Variable and Lexical Environments
>> function f() {
>>   // variable environment
>>   function xVarEnv() {return x}
>>   {
>>      //lexical environment
>>      print(xVarEnv());  //should be: undefined
>>      eval("var x=1");    //create in the variable environment
>>      print(xVarEnv());  //should be: 1
>>      eval("let x=2");     //create in the lexical environment
>>      eval("print(x)")     //should be: 2
>>      print(x);                 //should be: 2
>>      print(xVarEnv()); //should be: 1
>>   }
>>   print(xVarEnv()); //should be: 1
>> )
>> 
>> (note that the most interesting example have an inner block)
> 
> (Indeed.)
> 
> I don't like this because we make a pre-strict variation on 'let' that perpetuates the dynamic scope injection flaw in eval, whereby it can pollute its caller's scope with fresh bindings. This is just evil and I wish we'd never standardized it in ES1 for 'var'. I see no good coming from extending it to 'let' and 'const'.
> 
> And 'function' in block? That's a different case again because it wouldn't hoist. Indeed direct eval('function f(){...}') in non-strict code is analogous to the SpiderMonkey conditionally-compiled, dynamically-bound function in sub-statement pre-ES3 extension we are trying to kill.

To further clarify, consider this valid ES5 code that must continue to produce the same result in ES6 :

function f(condition,body1,body2) {
   if (condition) {
       var code = "function f() {+body1+"}";
       eval(code);
   } else {
       var code = "function f() {+body2+"}";
       eval(code);
   }
   f();
}

If eval was scoped exactly like a block, then this would fail because each function declarations would be block scoped to  a new block scope that was inaccessible at the actual call site. To get the necessary compatible behavior we have to hoist the function out of the block scope created for the eval all the way up to the body scope (the Variable Environment) of the function, just like var.  This is will be an additional, scoping variation for function declarations  that only comes into play for non-strict evals. 

Allen





More information about the es-discuss mailing list