I agree that this is in some sense the least surprising. But it is so
unpleasant that I think we should instead opt for the additional surprise
of #3 -- that a direct sloppy eval is block-like, even though there aren't
any curlies.


On Fri, Feb 14, 2014 at 8:03 AM, Jeremy Martin <jmar...@gmail.com> wrote:

> I rather hate to say it, but I would've actually expected:
>
> 4) Given that the eval'd string doesn't create anything typically
> considered a "block", the let binding would survive past the completion of
> the eval in non-strict mode:
>
>     (function() {
>           eval("
>               var answer=42;
>               let localToEval = true;
>            ");
>           console.log(answer);  // 42
>           console.log(localToEval);  // true
>     )();
>
>     (function() {
>           "use strict";
>           eval("
>               var answer=42;
>               let localToEval = true;
>            ");
>           console.log(answer);  // ReferenceError: answer is not defined
>           console.log(localToEval);  // ReferenceError: localToEval is not
> defined
>     )();
>
> I'm not necessarily arguing for that behavior, but weighing in since
> that's the behavior I would have expected based on existing ES5
> strict/non-strict/eval and ES6 let semantics...
>
>
> On Fri, Feb 14, 2014 at 10:40 AM, Allen Wirfs-Brock <al...@wirfs-brock.com
> > wrote:
>
>>
>> On Feb 14, 2014, at 5:49 AM, André Bargull wrote:
>>
>>  How about this?
>>
>> let x= 0;
>> if (1) eval("let x= 42; alert(x);"); //Is this in its own block?
>> alert(x);
>>
>>
>> `eval()` hasn't yet been updated to work with the new lexical declaration
>> forms, but I hope the example from above will be evaluated in a new block.
>> See https://bugs.ecmascript.org/show_bug.cgi?id=1788 for a related bug
>> report.
>>
>>
>> Goood point and this is something I need to specify in the next couple
>> weeks so let's look at the alternatives.
>>
>> First a quick refresher on ES5 era eval.
>>
>> In ES5, the binding behavior of direct eval differs between strict and
>> non-strict modes.
>>
>> In strict mode, each eval instantiates all declarations in a new
>> environment that is immediately nested within the current
>> LexicalEnvironment. The scoping behavior is essentially the same as if the
>> eval code was the body of an iife that occurred at the same place as the
>> eval call.  Bindings introduced by the eval code disappear after completion
>> of the eval.
>>
>> In non-strict mode, each eval instantiates all declarations in the
>> current VariableEnvironment; that is the most immediately enclosing
>> function or global environment.  Bindings introduced by the eval code
>> remain accessible from that VariableEnvironment after completion of the
>> eval.
>>
>> For example:
>> (function() {
>>       "use strict";
>>       eval("var answer=42");
>>       console.log(answer);  // ReferenceError: answer is not defined
>> })();
>>
>> (function() {
>>       eval("var answer=42");
>>       console.log(answer);  // 42
>> })();
>>
>> For ES6, it makes sense for strict mode evals to behave in this exact
>> same way. Each eval takes place in its own environment and no bindings
>> survive the completion of the eval.
>>
>> For ES6, non-strict evals of code containing only var or function
>> declarations must  have exactly the ES5 behavior  in order to maintain
>> compatibility.  But what about eval code that contains new declaration
>> forms (let/const/class) exclusively or in combination with var/function
>> declarations? Three possibilities come to mind:
>>
>> 1) Extend the ES5 semantics to include the new declaration forms.  For
>> example:
>>
>> (function() {
>>       eval("let answer=42");
>>       console.log(answer);  // 42
>> })();
>>
>> 2) Use the strict mode binding semantics  if the eval code directly
>> contains any of the new declaration forms:
>>
>> (function() {
>>       eval("
>>           var answer=42;
>>           let forceSeprateEnvironment = true;
>>        ");
>>       console.log(answer);  // ReferenceError: answer is not defined
>> })();
>>
>> 3) Combination.  use ES5 non-strict binding semantics for var/function
>> declarations but place let/const/class bindings into a per eval environment:
>>
>> (function() {
>>       eval("
>>           var answer=42;
>>           let localToEval = true;
>>        ");
>>       console.log(answer);  // 42
>>       console.log(localToEval);  // ReferenceError: localToEval is not
>> defined
>> )();
>>
>>
>> It would certainly be possible to specify #1, but I don't like it. Other
>> than for the global environment it would be cleaner if the new block
>> scope-able declarations  were never dynamically added to the environment.
>>
>> I think either #2 or #3 is plausible.  #2 is a simpler story but
>> introduces a refactoring hazard. If you have some existing eval code that
>>  defines some "global" functions or variables, then simply adding a
>> let/const/class declaration to the eval code ruins those global
>> declarations.
>>
>> I prefer the simplicity of #2, but I also worry about the WTF impact it
>> might have on evolving existing code.
>>
>> Can we get away with #2, or are we going to have to go with #3?  Are
>> there other alternatives?
>>
>> Allen
>>
>>
>>
>>
>>
>>
>>
>>
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss@mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>>
>
>
> --
> Jeremy Martin
> 661.312.3853
> http://devsmash.com
> @jmar777
>
> _______________________________________________
> es-discuss mailing list
> es-discuss@mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>


-- 
    Cheers,
    --MarkM
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to