Rationale of indirect eval and its subtle features

Dmitry A. Soshnikov dmitry.soshnikov at gmail.com
Fri Feb 18 16:13:05 PST 2011


On 18.02.2011 20:04, Allen Wirfs-Brock wrote:
> Here is another way to think about it.
>
> The built-in function object that is the initial value of the global 
>  "eval"  (defined in 15.1.2.1) is a non-strict function. Hence 
> anything it does defaults to "non-strict" and it uses the global 
> environment as the VariableEnvironment for the code it evaluates. 
>  However, if the argument code contains an use strict directive, then 
> it uses a new child environment of the global environment as the 
> VariableEnvironment.   This is all specific defined behavior of the 
> built-in eval function object and is completely independent of who 
> calls the function or how the caller accessed the function.
>

Yes, it's clear how it looks/implemented _technically_, however doesn't 
explain a practical rationale. So at the moment I have the following 
conclusion and understanding (please correct me if I'm mistaken):

An indirect `eval` introduced into ES spec not because of some/any 
security reason (what I mentioned earlier in my explanations), and even 
not because of some _practical_ reasons, but just because of _complexity 
of the implementation_. I.e. _initially_ indirect `eval` is related with 
the implementation level only (only after that JS devs adapted this 
_technique_ for already mentioned getting of the global object in strict 
mode).

Is this explanation correct?

> An "indirect eval" is any invocation of the above function.
>

This is a subtle case, thanks (taking into account your following 
explanation of with the inlining the code to the call site). So, 
_abstractly_ (? -- I can't say precisely whether it's _technically_ 
though, since I'm not the implementer), if _syntactically_ we use this form:

eval(...)

it isn't even an `eval` call, but just an inlining. I can imagine it 
abstractly as (with providing a "sandbox" environment):

(function foo() {
   eval("var x = 10;")
})();

is _abstractly_ desugars (inline) into:

(function foo() {
   (function __directEval(configurableBindings?) {
     var x = 10;
   })(true);
})();

 From this position it looks just an optimization technique. And if we 
do this:

var myEval = eval;
myEval("var x = 10;");

we already can't inline the `eval` at parsing stage (?), right? And if 
we'd to pass the information about strictness of the surrounding 
context, we just should pass additional argument the `myEval`, yep? 
Though, I don't see which issue this passing of this additional argument 
can lead (which by the way?).

> A "direct eval" is essentially a special syntactic from in the ES5 
> language with its own specific semantics. Some people have talked 
> about it as the "eval" operator.  A direct eval does not call the 
> built-in eval function object.  Instead, it has its own slightly 
> different semantics that can be directly implemented at the call site.

Yes, it was new for me (and for any JS dev I guess). And how it looks I 
tried to describe above (is that understanding is correct?).

>  These semantics include access to the immediately surrounding 
> LexicalEnvironment and the propagation of strictness into the eval code.
>

Yep, if to accept the inheriting of the strictness by the inner 
functions (with which I desugared the eval inlining).

Thanks again, Allen, it seems clear now. But the main thing which I 
found out from it, is that _initially_ it's _not about JS-programming_, 
it's just an _optimization technique_ for the _implementers_.

Dmitry.

> Allen
>
>
> On Feb 18, 2011, at 4:52 AM, Dmitry A. Soshnikov wrote:
>
>> Have no idea what with mail sever again, there is no this message 
>> there (links in message?). The original question is below:
>>
>> On 18.02.2011 11:51, Dmitry A. Soshnikov wrote:
>>> Hello,
>>>
>>> As is known, indirect `eval` evaluates in the global context (this 
>>> note is not for the TC-39 group of course, but for all other who 
>>> read this list). But what is the big rationale of that indirect eval 
>>> is allowed to create a global binding even _regardless_ the fact 
>>> that the global code is _strict_?
>>>
>>> I.e.:
>>>
>>> "use strict";
>>>
>>> eval("var x = 10;"); // direct
>>> this.eval("var y = 20;"); // indirect
>>>
>>> console.log(typeof x, typeof y); // "undefined", "number"
>>>
>>> The only _practical_ rationale of the indirect `eval` regarding the 
>>> strict mode is that via its call it's possible to get the global 
>>> object via `this` value from any place (since just returning `this` 
>>> won't work as it's set to `undefined` in a simple function call):
>>>
>>> var global = (function () { return this; })(); // ES3, non-strict 
>>> ES5 way
>>>
>>> var global = ("indirect", eval)("this"); // strict ES5
>>>
>>> Which else practical/theoretical/academical rationales of the 
>>> indirect eval are? And what again the rationale that it's allowed to 
>>> create the global binding (i.e. not in the "sandbox" environment, 
>>> but reusing `VariableEnvironment` of the "caller" -- not a direct 
>>> caller though, but the adjusted -- the global scope)? Could you 
>>> clarify this, I want to give a more concrete explanations for my 
>>> readers.
>>>
>>> P.S.:
>>>
>>> Just recently Allen brought a good addition (well, a reminder even 
>>> better to say, since I also wanted to add it ;) to mention this 
>>> subtle case with indirect eval and it's ability to affect the global 
>>> environment regardless the strict mode: 
>>> http://dmitrysoshnikov.com/ecmascript/es5-chapter-2-strict-mode/#comment-5831
>>>
>>> It's without doubts a very needed addition and as is said -- a 
>>> subtle case, but still -- what are the exact rationales for that? I 
>>> mentioned this case in Allen's blog before, and though that this is 
>>> a bug of the spec -- 
>>> http://www.wirfs-brock.com/allen/posts/39#comment-46
>>>
>>> Allen answered that this is related with complexity of 
>>> implementation, here:
>>>
>>> "An /indirect/ eval called from strict code is strict only if the 
>>> eval code explicit contains an “use strict;” directive. It does not 
>>> “inherit” the strictness of its caller.
>>>
>>> Every call is potentially an indirect eval call. If the strictness 
>>> of indirect evals depended upon the strictness of the caller then we 
>>> would have to pass the strictness of the caller through every call. 
>>> That would require either an extra implicit parameter on every call 
>>> or the ability to a callee to examine the call stack to to determine 
>>> the strictness of its caller. We don’t want to force this on 
>>> implementations."
>>>
>>> The basic idea is seems clear -- we need to pass a flag that the 
>>> code of an inner function (from which indirect `eval` was called) is 
>>> strict, but if the _global_ code is strict -- and indirect `eval` 
>>> always evaluates in the global context, and moreover, if the global 
>>> code is strict that means _any_ inner function (except those which 
>>> are created via `Function` constructor and have no own strictness) 
>>> is automatically also strict:
>>>
>>> "use strict";
>>>
>>> (function foo() {
>>>   // this code is also strict
>>>   ("indirect", eval)("var x = 10;");
>>> })();
>>>
>>> console.log(x); // 10
>>>
>>> is it also required to pass special flags to handle this case?
>>>
>>> Thanks,
>>> Dmitry.
>>
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
>> https://mail.mozilla.org/listinfo/es-discuss
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20110219/3f957349/attachment.html>


More information about the es-discuss mailing list