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