On 19.02.2011 21:23, Allen Wirfs-Brock wrote:
The distinction between a direct eval and an eval first appears in
Ecma-262, Edition 2 which said: "If value of the *eval *property is
used in any way other than a direct call (that is, other than by the
explicit use of its name as an /Identifier /which is the
/MemberExpression /in a /CallExpression/), or if the *eval *property
is assigned to, an *EvalError *exception may be thrown."
Note that the ES2 definition left support for indirect eval as an
implementation option. Some browsers tried to implement throwing on
EvalError but they discovered that this was incompatible with the web.
So they implemented globally scoped indirect eval which proved to be
compatible with the web. By the time of the drafting of ES5 the
situations was that that some browsers implemented indirect and direct
evals identically and some browsers implemented globally scoped
indirect eval. No browser made use of the specification permitted
EvalError.
Yeah, I see. So this is all about the lexical (static) scope. I.e. the
closured lexical environment of the built-in `eval` is the global
environment, therefore it has access only for the global bindings, right?
It seems also explains that the `Function`'s code is always evaluated in
the global context -- it's in contrast with direct `eval`'s which isn't
a function call at all. Is it so (regarding `Function`)?
For ES5 we wanted to eliminate any implementation options from the
eval spec and to make it compatible with the web. Globally scoped
indirect eval served was the solution we choose. The rest of the
details including the treatment of strict code follow from that decision.
Yep, it's clear.
Also note that the term "indirect eval" is never used in the
normative parts of the ES5 specification. It only distinguishes
"direct calls to eval" as the special case. The term "indirect eval"
is only used in Annex D.
Yes, though, exactly the term "indirect" became the most popular in this
case.
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?
It's not how I would state it. As a general design principle the
behavior of any function, when called should only depend upon the
environment it was defined in and the arguments that are explicitly
passed to it.
Yes, as I mentioned -- a normal lexical scope implementation.
eval, as a built-in function, is defined within the global
environment and it has no explicit arguments that expose the scope of
its caller. Hence, it only is allowed to manipulate the global scope.
Yes, only if an implementation can handle its invocation differently. I
see that you say that built-in `eval` is just a simple function which
obey the same lexical scoping rules and therefore all the identifiers
lookup is made in statically saved environment.
On the other hand, why the implementation cannot treat the `eval`'s
activation differently? Why not to save its original lexical environment
(that is, global), set it to the environment of the caller and after the
evaluation again restore it?
Direct eval, is the "odd duck". There is no normal function mechanism
that permits its behavior. Rather than extending the semantics of
function calls in general (any call may be an indirect eval call) we
special case the handling of direct eval in 10.4.2 step 2.
Hm.. and this is the answer on my previous question. No special
semantics with replacing saved lexical environment.
Implementation impact is something we're alway considering, but it
isn't needed to justify this behavior. If you are going to treat eval
as a normal function object then it needs to be callable as such.
Yes, it's clear now -- the lexical scope and a common functions'
behavior -- that's the main reason.
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);
})();
Note: this abstract representation doesn't explain also dynamic
eval's string. i.e. when some variable should be determined at
runtime, when the environment is formed:
(function foo(x) {
eval("var x = " + x + ";")
})(10);
How here the inlining can work?
The declaration instantiation rules get in the way of these simple
inlining models. Consider this:
function outer() {
var x=0;
(function () {
x=1;
var x=2}
)();
return x; //returns 0
}
compared to
function outer() {
var x=0;
(function () {
x=1;
eval(" var x=2");}
)();
return x; //returns 1
}
Yeah, I know that the "hoisting" breaks my simplified model of `eval`'s
inlining, but I wanted just to imagine how it is made. If to exclude the
"hoisting" (i.e. all definitions are made sequentially in runtime), then
direct `eval`'s desugars quite normally.
Thanks, again Allen, I think at this step it became completely clear.
(probably I'll write a small blog-post note with explaining all this
suble cases and especially why Function("...") in contrast with (direct)
`eval` executes in the global scope).
Dmitry.
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
[email protected] <mailto:[email protected]>
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss