block scope + direct non-strict eval

Brendan Eich brendan at
Tue Jan 31 11:20:39 PST 2012

Allen Wirfs-Brock wrote:
> 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();
> }

We are talking about taking the variant of this code that removes the 
eval calls by declaring functions in blocks, and breaking it. True, the 
two are different cases. But the reason we hope we can break

function f(condition,val1,val2) {
     if (condition) {
         function f() { return val1; }
     } else {
         function f() { return val2; }

is because it does not have interoperable semantics across major 
browsers. When we banned function-in-block in ES5 strict, we did find 
code that had "use strict"; prematurely applied before ES5-strict 
implementations were available for testing, or applied via concatenation 
of scripts. All such function in block cases were sane:

function f(condition,val1,val2) {
     if (condition) {
         function f() { return val1; }
         val2 = f();

     return val2;

or similar. The function-in-block not only dominates all its uses, all 
uses are contained by the block in which the function is declared.

> 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.

You're right, and this is what the SpiderMonkey function-in-substatement 
provided (limited conditional compilation without eval). Crazy as people 
say, and we want to remove it. Is it unthinkable to break compatibility 
for the eval expansion?

>   This is will be an additional, scoping variation for function declarations  that only comes into play for non-strict evals.

If we have to keep compatibility, then we have 'function' requiring a 
special case compared to 'let' with your option 2. Or we take option 1 
and have all the forms, new (let and const) and old (var and function) 
pollute non-strict direct eval's dynamic scope. Gah.


More information about the es-discuss mailing list