Strict mode eval

# Andreas Rossberg (14 years ago)

I'm a bit puzzled regarding the meaning of "use strict" in the context of higher-order uses of eval.

Consider the following program. What is the expected result of the latter calls?


var x = 3

function call_eval() { x = 3; eval("var x = 4"); return x } function call_eval_strict() { "use strict"; x = 3; eval("var x = 4"); return x }

function get_eval() { return eval } function get_eval_strict() { "use strict"; return eval }

function call_f(f) { x = 3; f("var x = 4"); return x } function call_f_strict(f) { "use strict"; x = 3; f("var x = 4"); return x }

call_eval() // 4 call_eval_strict() // 3

call_f(eval) // 4 call_f(get_eval()) // 4 call_f(get_eval_strict()) // ?

call_f_strict(eval) // ? call_f_strict(get_eval()) // ? call_f_strict(get_eval_strict()) // ?

(function() { "use strict"; return call_f_strict(get_eval_strict()) })() // ?

V8 bleeding edge currently returns 4 for all of the latter calls, but that does not seem quite right to me. Especially for the last two cases that would practically amount to a loop hole in strict mode. But where does the spec say differently?

I'd be happy for any enlightenment.

Thanks,

# Oliver Hunt (14 years ago)

On May 10, 2011, at 10:16 AM, Andreas Rossberg wrote:

I'm a bit puzzled regarding the meaning of "use strict" in the context of higher-order uses of eval.

Consider the following program. What is the expected result of the latter calls?


var x = 3

function call_eval() { x = 3; eval("var x = 4"); return x }

sets global x to 3, eval operator introduces a local binding for x and sets it to 4. We return the local binding (4) global x is 3

function call_eval_strict() { "use strict"; x = 3; eval("var x = 4"); return x }

sets global x binding to 3, eval operator gets its own environment record with a binding for x, it sets it to 4, function returns value of global x binding

function get_eval() { return eval } function get_eval_strict() { "use strict"; return eval }

Both return the same eval function (not the operator)

function call_f(f) { x = 3; f("var x = 4"); return x } function call_f_strict(f) { "use strict"; x = 3; f("var x = 4"); return x }

call_eval() // 4 call_eval_strict() // 3

All your other calls are calls to the eval function, not the eval operator, and on those cases the containing environment record is the global scope.


V8 bleeding edge currently returns 4 for all of the latter calls, but that does not seem quite right to me. Especially for the last two cases that would practically amount to a loop hole in strict mode. But where does the spec say differently?

eval is a little gnarly in ES5, essentially there are two modes: eval the function and eval the operator.

Any piece of code (ignoring overrides/shadowing) that does eval(....)

Is using the eval operator, in which case the containing environment record of the code executed by eval, is the environment record in which the call is made.

Any form of indirection to eval that leads to it being called by a name other than eval means you're calling the function form. In the function form the containing environment record for the code executed by eval is the global env. record.

I can't recall off the top of my head whether function f(eval) { eval(...) } will result in behaviour that's considered to be the operator or function form (i'can't recall whether th semantics define the env. record the resolved eval must be boun

# Juriy Zaytsev (14 years ago)

On Tue, May 10, 2011 at 1:16 PM, Andreas Rossberg <rossberg at google.com>wrote:

I'm a bit puzzled regarding the meaning of "use strict" in the context of higher-order uses of eval.

Consider the following program. What is the expected result of the latter calls?


var x = 3

function call_eval() { x = 3; eval("var x = 4"); return x } function call_eval_strict() { "use strict"; x = 3; eval("var x = 4"); return x }

function get_eval() { return eval } function get_eval_strict() { "use strict"; return eval }

function call_f(f) { x = 3; f("var x = 4"); return x } function call_f_strict(f) { "use strict"; x = 3; f("var x = 4"); return x }

call_eval() // 4 call_eval_strict() // 3

This is correct.

call_f(eval) // 4 call_f(get_eval()) // 4 call_f(get_eval_strict()) // ?

The last one should return 4 as well. There's no difference between eval, get_eval(), and get_eval_strict() in this context. All of them are essentially a reference to a built-in, global eval function. Strict mode only affects calling behavior of eval. The retrieval of eval object is still the same.

But something else comes into play here, and that something is indirect eval call.

call_f_strict(eval) // ? call_f_strict(get_eval()) // ? call_f_strict(get_eval_strict()) // ?

When call_f_strict executes and eval is called from within it, it is actually an indirect eval call. Why? Because the reference name is not eval, but f and so it doesn't satisfy direct eval call requirement (see es5.github.com/#x15.1.2.1.1)

In ES5 indirect eval calls execute in global execution context ( es5.github.com/#x10.4.2) and so all 3 last calls actually end up executing var x = 4 in global scope (overwriting global x).

You can see that if you were to create local x variable in call_f_strict that x would be unaffected by eval calls.

function call_f_strict(f) { "use strict"; var x = 3; f("var x = 4"); return x; // should return 3, since x = 4 was executed outside of this local scope }

For more on indirect eval calls — perfectionkills.com/global-eval-what-are-the-options

[...]

# Lasse Reichstein (14 years ago)

On Tue, 10 May 2011 19:16:40 +0200, Andreas Rossberg <rossberg at google.com>

wrote:

I'm a bit puzzled regarding the meaning of "use strict" in the context of higher-order uses of eval.

Consider the following program. What is the expected result of the
latter calls?


var x = 3

function call_eval() { x = 3; eval("var x = 4"); return x } function call_eval_strict() { "use strict"; x = 3; eval("var x = 4");
return x }

function get_eval() { return eval } function get_eval_strict() { "use strict"; return eval }

These two, get_eval and get_eval_strict, should be equivalent. They both
return the same value, the eval function.

function call_f(f) { x = 3; f("var x = 4"); return x } function call_f_strict(f) { "use strict"; x = 3; f("var x = 4"); return
x }

call_eval() // 4 call_eval_strict() // 3

Agree.

call_f(eval) // 4 call_f(get_eval()) // 4 call_f(get_eval_strict()) // ?

All equivalent, they call the same function with the same argument.

call_f_strict(eval) // ? call_f_strict(get_eval()) // ? call_f_strict(get_eval_strict()) // ?

And again equivalent, so the question is what the result is.

The call to f in call_f_strict is an indirect call to eval in a strict context. That means that the eval code is not strict code (10.1.1) since it's not a direct call, and it doesn't contain the "use strict" directive.

I.e., its evaluated as a normal indirect call to eval, which uses the global environment as VariableEnvironment and LexicalEnvironment, and the "var x = 4;" will overwrite the global variable x.

I.e., 4 is the correct answer.

(function() { "use strict"; return call_f_strict(get_eval_strict())
})() // ?

And this is the same (same function called with same argument). That it happens in a strict environment doesn't change anything.


V8 bleeding edge currently returns 4 for all of the latter calls, but that does not seem quite right to me. Especially for the last two cases

Seems this is correct.

that would practically amount to a loop hole in strict mode. But where does the spec say differently?

It's only a loop hole in strict mode if the strict code has access to the unmodified eval function. You can get out of strict mode too, if you have access to the original Function constructor. What you can't do is to execute non-strict code inside a strict-mode
context.

# Allen Wirfs-Brock (14 years ago)

On May 10, 2011, at 10:50 AM, Oliver Hunt wrote:

I can't recall off the top of my head whether function f(eval) { eval(...) } will result in behaviour that's considered to be the operator or function form (i'can't recall whether th semantics define the env. record the resolved eval must be boun

--Oliver

This s a direct eval, if f is declared in a non-strict context and the original built-in eval function is passed as the argument to f. Put simply, to be a "direct eval" the invocation of the function must use the identifier name "eval" and the value the identifier must be the built-in eval function. However, the binding for "eval" doesn't need to come from the global environment record.

If f is defined in a strict context, the use of eval as a formal parameter name is an early error.

# Andreas Rossberg (14 years ago)

Thanks to everybody for clearing up my confusion. The thing I had missed in the spec was Section 10.4.2. And of course, my example was too simplistic because it couldn't distinguish caller and global context.

At the risk of reviving old discussions, are there any sources explaining the rationale behind the current design? The "obvious" solution to me would have been having two internal variants/modes of (or "entry points" to) the eval function, one strict, one non-strict. And depending on the lexical strict mode, the identifier "eval" would be bound to the right one.

Thanks,

# Mark S. Miller (14 years ago)

On Wed, May 11, 2011 at 4:42 AM, Andreas Rossberg <rossberg at google.com>wrote:

Thanks to everybody for clearing up my confusion. The thing I had missed in the spec was Section 10.4.2. And of course, my example was too simplistic because it couldn't distinguish caller and global context.

At the risk of reviving old discussions, are there any sources explaining the rationale behind the current design? The "obvious" solution to me would have been having two internal variants/modes of (or "entry points" to) the eval function, one strict, one non-strict. And depending on the lexical strict mode, the identifier "eval" would be bound to the right one.

I don't think I understand the suggestion. What would the following code do:

// non-strict outer context

function f(eval) {
  var f = eval;
  function g() {
    "use strict";
    eval(str); // [1]
    (1,eval)(str); // [2]
    f(str); // [3]
  }
}

[1] If the outer eval is bound to the global eval function then this is a direct eval, which therefore lexically inherits strictness. So no problem here.

[2] The 'eval' identifier is bound in non-strict code and used in strict code.

[3] Strict code makes no use here of a lexical binding of the identifier "eval".

A previous approach which we rejected was to make strictness dynamically scoped, so all three of the above calls would do strict evals. This was rejected to avoid the problems of dynamic scoping. Are you suggesting a rule that would affect #2 but not #3? If so, IIRC no such rule was previously proposed.

# Andreas Rossberg (14 years ago)

On 11 May 2011 18:31, Mark S. Miller <erights at google.com> wrote:

On Wed, May 11, 2011 at 4:42 AM, Andreas Rossberg <rossberg at google.com> wrote:

Thanks to everybody for clearing up my confusion. The thing I had missed in the spec was Section 10.4.2. And of course, my example was too simplistic because it couldn't distinguish caller and global context.

At the risk of reviving old discussions, are there any sources explaining the rationale behind the current design? The "obvious" solution to me would have been having two internal variants/modes of (or "entry points" to) the eval function, one strict, one non-strict. And depending on the lexical strict mode, the identifier "eval" would be bound to the right one.

I don't think I understand the suggestion. What would the following code do:     // non-strict outer context     function f(eval) {       var f = eval;       function g() {         "use strict";         eval(str); // [1]         (1,eval)(str); // [2]         f(str); // [3]       }     } [1] If the outer eval is bound to the global eval function then this is a direct eval, which therefore lexically inherits strictness. So no problem here. [2] The 'eval' identifier is bound in non-strict code and used in strict code. [3] Strict code makes no use here of a lexical binding of the identifier "eval".

A previous approach which we rejected was to make strictness dynamically scoped, so all three of the above calls would do strict evals. This was rejected to avoid the problems of dynamic scoping. Are you suggesting a rule that would affect #2 but not #3? If so, IIRC no such rule was previously proposed.

I'm actually suggesting plain lexical scoping. :)

Basically, what I'm saying is that the directive "use strict" could simply amount to shadowing the global eval via an implicit "var eval = eval_strict" (unless global eval has already been shadowed lexically). So all uses of the identifier `eval' in that scope would refer to its strict version, no matter when, where, or how you ultimately invoke it. Consequently, all your three examples would behave the same, only depending on the argument to f.

Re dynamic scoping: in fact, I would claim that the current rule is a form of dynamic scoping -- eval behaves differently when its caller is strict. Except that this rule only applies when the syntactic identifier in the call happens to be "eval". Regardless of the above, I wonder why this special case was introduced. Why is the rule not applied to all applications uniformly? I feel that I am missing something.

# Mark S. Miller (14 years ago)

On Wed, May 11, 2011 at 10:31 AM, Andreas Rossberg <rossberg at google.com>wrote:

On 11 May 2011 18:31, Mark S. Miller <erights at google.com> wrote:

On Wed, May 11, 2011 at 4:42 AM, Andreas Rossberg <rossberg at google.com> wrote:

Thanks to everybody for clearing up my confusion. The thing I had missed in the spec was Section 10.4.2. And of course, my example was too simplistic because it couldn't distinguish caller and global context.

At the risk of reviving old discussions, are there any sources explaining the rationale behind the current design? The "obvious" solution to me would have been having two internal variants/modes of (or "entry points" to) the eval function, one strict, one non-strict. And depending on the lexical strict mode, the identifier "eval" would be bound to the right one.

I don't think I understand the suggestion. What would the following code do: // non-strict outer context function f(eval) { var f = eval; function g() { "use strict"; eval(str); // [1] (1,eval)(str); // [2] f(str); // [3] } } [1] If the outer eval is bound to the global eval function then this is a direct eval, which therefore lexically inherits strictness. So no problem here. [2] The 'eval' identifier is bound in non-strict code and used in strict code. [3] Strict code makes no use here of a lexical binding of the identifier "eval".

A previous approach which we rejected was to make strictness dynamically scoped, so all three of the above calls would do strict evals. This was rejected to avoid the problems of dynamic scoping. Are you suggesting a rule that would affect #2 but not #3? If so, IIRC no such rule was previously proposed.

I'm actually suggesting plain lexical scoping. :)

Basically, what I'm saying is that the directive "use strict" could simply amount to shadowing the global eval via an implicit "var eval = eval_strict" (unless global eval has already been shadowed lexically). So all uses of the identifier `eval' in that scope would refer to its strict version, no matter when, where, or how you ultimately invoke it. Consequently, all your three examples would behave the same, only depending on the argument to f.

I don't understand. If "use strict" implicitly introduces a "var eval = eval_strict;" at the position it occurs, then wouldn't #3 in my example still evaluate non-strict?

I'll answer the rest once I understand your proposal.

# felix (14 years ago)

I think he's proposing that the 'eval' function would be a magical function that can inspect its calling environment to determine whether it's being called in a lexically strict context or not, and based on that it would act like the strict eval operator, or not.

# Mark S. Miller (14 years ago)

On Wed, May 11, 2011 at 11:41 AM, felix <felix8a at gmail.com> wrote:

I think he's proposing that the 'eval' function would be a magical function that can inspect its calling environment to determine whether it's being called in a lexically strict context or not, and based on that it would act like the strict eval operator, or not.

That's exactly what I'm trying to determine. Such magical dynamic inspection of the caller's lexical context would be a form of dynamic scoping. Nowhere else in the language can a callee detect a caller's strictness.

# Allen Wirfs-Brock (14 years ago)

On May 11, 2011, at 11:51 AM, Mark S. Miller wrote:

On Wed, May 11, 2011 at 11:41 AM, felix <felix8a at gmail.com> wrote: I think he's proposing that the 'eval' function would be a magical function that can inspect its calling environment to determine whether it's being called in a lexically strict context or not, and based on that it would act like the strict eval operator, or not.

That's exactly what I'm trying to determine. Such magical dynamic inspection of the caller's lexical context would be a form of dynamic scoping. Nowhere else in the language can a callee detect a caller's strictness.

This is the key point that I haven't seen otherwise mentioned on this thread. Classically JS eval as implemented by browsers required knowledge about its calling environment that generally isn't passed by a normal function call. To make this work, either this extra information has to be passed in every call to any function (any call might be to an aliased eval call) or there has to be a dynamic scoping mechanism that allows eval to reach up the stack and get out of band information from it caller. Neither of these were things we wanted to require of implementations in ES5.

"Direct eval" (or the eval operator, as Oliver refers to it) is a way to (mostly) statically identify eval calls and to do special case processing to make the caller environment information available for eval processing. "indirect evals" are just regular function calls and not special environment information is passed or otherwise made available. So, the built-in eval function when indirectly involved is limited to using the global environment.

This has nothing to do with strict mode.

# Andreas Rossberg (14 years ago)

On 11 May 2011 20:30, Mark S. Miller <erights at google.com> wrote:

On Wed, May 11, 2011 at 10:31 AM, Andreas Rossberg <rossberg at google.com> wrote:

On 11 May 2011 18:31, Mark S. Miller <erights at google.com> wrote:

On Wed, May 11, 2011 at 4:42 AM, Andreas Rossberg <rossberg at google.com> wrote:

Thanks to everybody for clearing up my confusion. The thing I had missed in the spec was Section 10.4.2. And of course, my example was too simplistic because it couldn't distinguish caller and global context.

At the risk of reviving old discussions, are there any sources explaining the rationale behind the current design? The "obvious" solution to me would have been having two internal variants/modes of (or "entry points" to) the eval function, one strict, one non-strict. And depending on the lexical strict mode, the identifier "eval" would be bound to the right one.

I don't think I understand the suggestion. What would the following code do:     // non-strict outer context     function f(eval) {       var f = eval;       function g() {         "use strict";         eval(str); // [1]         (1,eval)(str); // [2]         f(str); // [3]       }     } [1] If the outer eval is bound to the global eval function then this is a direct eval, which therefore lexically inherits strictness. So no problem here. [2] The 'eval' identifier is bound in non-strict code and used in strict code. [3] Strict code makes no use here of a lexical binding of the identifier "eval".

A previous approach which we rejected was to make strictness dynamically scoped, so all three of the above calls would do strict evals. This was rejected to avoid the problems of dynamic scoping. Are you suggesting a rule that would affect #2 but not #3? If so, IIRC no such rule was previously proposed.

I'm actually suggesting plain lexical scoping. :)

Basically, what I'm saying is that the directive "use strict" could simply amount to shadowing the global eval via an implicit "var eval = eval_strict" (unless global eval has already been shadowed lexically). So all uses of the identifier `eval' in that scope would refer to its strict version, no matter when, where, or how you ultimately invoke it. Consequently, all your three examples would behave the same, only depending on the argument to f.

I don't understand. If "use strict" implicitly introduces a "var eval = eval_strict;" at the position it occurs, then wouldn't #3 in my example still evaluate non-strict?

Assume that

  • we distinguish two variants of the eval function, strict and non-strict -- let's call these values EVAL_s and EVAL_ns.
  • initially (in global scope), the identifier `eval' is bound to EVAL_ns.
  • in a strict mode scope it will be considered rebound to EVAL_s instead (unless it has already been shadowed by user code anyway).

(In addition, at least in strict mode, the only calls to eval' that are considered _direct_ calls would be those whereeval' statically refers to the initial binding or one of the implicit strict-mode rebindings -- i.e., where it has not been shadowed by the user.)

In your example, the eval' identifier is already shadowed by the function parameter, so the inner "use strict" would have no effect on it -- in that scopeeval' is just an ordinary identifier. Consequently, all 3 examples would behave alike and are non-direct calls. Whether strict or not solely depends on what you pass in to f:

// non-strict scope f(eval) // EVAL_ns (function() { "use strict"; f(eval) })() // EVAL_s f((function() { "use strict"; return eval })()) // EVAL_s

Does that make sense? The idea is that strict/non-strict is resolved w.r.t. the static scope where the identifier `eval' occurs. With this semantics, there would be no way in strict mode to access non-strict eval, unless it is explicitly provided by someone. With the current rules that is not the case, because you can easily defeat strict mode by a random indirection, e.g.:

"use strict"; var e = eval e("var oops = 666") // pollutes the global object, although the whole program is in strict mode

I'm not sure whether that was intentional or not, but it feels strange.

# Andreas Rossberg (14 years ago)

On 11 May 2011 23:15, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

"Direct eval"  (or the eval operator, as Oliver refers to it) is a way to (mostly) statically identify eval calls and to do special case processing to make the caller environment information available for eval processing.  "indirect evals" are just regular function calls and not special environment information is passed or otherwise made available.  So, the built-in eval function when indirectly involved is limited to using the global environment. This has nothing to do with strict mode.

Sorry, I should have been clearer. To clarify: my follow-up question was only tangentially related to the question of direct calls -- it mainly was about how eval inherits strict mode.

The one bit where these questions are somewhat related is the "(mostly)" bit in your reply. Is there a reason for this "mostly", which, I would argue, is a form of dynamic scoping?

# Allen Wirfs-Brock (14 years ago)

On May 12, 2011, at 2:10 AM, Andreas Rossberg wrote:

The one bit where these questions are somewhat related is the "(mostly)" bit in your reply. Is there a reason for this "mostly", which, I would argue, is a form of dynamic scoping?

/Andreas

The "mostly" refers to the fact the the actual value of the eval binding has to be checked at runtime to be sure that a call via the identifier "eval" is an actual direct eval operation.

For example:

function foo() { var x=5; eval("x"); //this looks like a direct eval. Is it really? }

Needs to "compile" into something like:

function foo() { var x=5; if (eval===builtinEvalFunction) { //perform an inline eval operation using the current lexical environment and strict mode } else eval("x"); //do a regular call to some function that isn't the built-9in eval }

This is necessary, because the global binding for "eval" might be changed or because there might be a binding of "eval" in an surrounding scope.

# Andreas Rossberg (14 years ago)

On 12 May 2011 17:47, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On May 12, 2011, at 2:10 AM, Andreas Rossberg wrote:

The one bit where these questions are somewhat related is the "(mostly)" bit in your reply. Is there a reason for this "mostly", which, I would argue, is a form of dynamic scoping?

[...] This is necessary, because the global binding for "eval" might be changed

Ouch, right.

or because there might be a  binding of "eval" in an surrounding scope.

I see -- which, specifically, might have been introduced after the fact via `with' or non-strict eval.

I guess I still have a blind spot on the various ways of messing up static scoping. But I'm working on it. :) Anyway, thanks for pointing it out.

# Mark S. Miller (14 years ago)

On Thu, May 12, 2011 at 2:08 AM, Andreas Rossberg <rossberg at google.com>wrote: [...]

Assume that

  • we distinguish two variants of the eval function, strict and non-strict -- let's call these values EVAL_s and EVAL_ns.
  • initially (in global scope), the identifier `eval' is bound to EVAL_ns.
  • in a strict mode scope it will be considered rebound to EVAL_s instead (unless it has already been shadowed by user code anyway).

(In addition, at least in strict mode, the only calls to eval' that are considered _direct_ calls would be those whereeval' statically refers to the initial binding or one of the implicit strict-mode rebindings -- i.e., where it has not been shadowed by the user.)

I think the core insight here is good, and had it been made in time, could have led to a better semantics than what we adopted into ES5. I like the idea that ' "use strict";' effectively inserts a DeclarativeEnvironmentRecord binding 'eval' to EVAL_s, though I'd put this record on the stack at the strict/non-strict boundary rather than just above the global object. IIRC, no one has previous suggested anything remotely like this. Of course, it's too late to fix ES5, but perhaps we can still apply your insights to improve the eval situation in ES-next and SES.

This should be doable because both ES-next and SES effectively remove the global object from the bottom of the scope chain and prevent local rebinding of 'eval'. Thus the outer binding for eval in scope for ES-next and SES code can differ from window.eval. SES-on-ES5 does this already, but at the cost of breaking direct eval inside SES code, since 'eval' in that code no longer has its original binding to EVAL_ns.

The key to preserving direct eval is your next insight above: that the set of such built-in eval variants form some kind of equivalence class, so that an apparent direct eval call is actually a direct eval call if its binding for 'eval' is any of the eval functions in that equivalence class.

Even better, since 'eval' cannot be rebound by ES5/strict, ES-next, or SES code, and since "eval(str)" is effectively a special form anyway, why not remove the dynamic "and if 'eval' is bound to the original global eval function" condition from direct eval? Why not just treat "eval(str)" as a direct eval special form independent of what 'eval' is bound to in that scope? Then, module loaders could be used to introduce different top level bindings for 'eval', as used for indirect eval calls, without breaking the direct eval special form.

The one downside is an extra burden on source-to-source rewriters: they would also need to rewrite the direct eval call 'eval(str)' into approximately 'eval(rewrite(str))', which requires that the rewriter itself be written in JavaScript and downloaded to the client. Given how large a parser needs to be to accurately parse JavaScript, this is an unfortunate burden. Despite this burden, I think we should consider removing this dynamic condition from the ES-next direct eval special form.

# Andreas Rossberg (14 years ago)

On 13 May 2011 01:50, Mark S. Miller <erights at google.com> wrote:

Assume that

  • we distinguish two variants of the eval function, strict and non-strict -- let's call these values EVAL_s and EVAL_ns.
  • initially (in global scope), the identifier `eval' is bound to EVAL_ns.
  • in a strict mode scope it will be considered rebound to EVAL_s instead (unless it has already been shadowed by user code anyway).

(In addition, at least in strict mode, the only calls to eval' that are considered _direct_ calls would be those whereeval' statically refers to the initial binding or one of the implicit strict-mode rebindings -- i.e., where it has not been shadowed by the user.)

I think the core insight here is good, and had it been made in time, could have led to a better semantics than what we adopted into ES5. I like the idea that ' "use strict";' effectively inserts a DeclarativeEnvironmentRecord binding 'eval' to EVAL_s, though I'd put this record on the stack at the strict/non-strict boundary rather than just above the global object.

Yes, my previous description of "shadowing" `eval' at the point of "use strict" was meant to describe just that.

Even better, since 'eval' cannot be rebound by ES5/strict, ES-next, or SES code, and since "eval(str)" is effectively a special form anyway, why not remove the dynamic "and if 'eval' is bound to the original global eval function" condition from direct eval? Why not just treat "eval(str)" as a direct eval special form independent of what 'eval' is bound to in that scope?

That's what I tried to suggest in the parenthesized paragraph above, and it was the reason for my question to Allan.

The difficulty in ES5 would be that scoping is not really static -- not even in strict-mode code, which might still be surrounded by non-script scopes shadowing eval' dynamically (espwith'). But for Harmony it'd be nice.

Thanks,

# Mark S. Miller (14 years ago)

I think this is the kind of incremental refinement of the details of existing features that we can legitimately consider after May without setting a bad precedent. Would you be interested in turning these ideas into a strawman for, say, the July meeting?

Unless there's a problem with this approach I'm not noticing, I think it would be a welcome cleanup of a messy part of the language -- conditioned on an ES-next opt in of course.

# Andreas Rossberg (14 years ago)

Sure, sounds good. I will look into it.

Thanks,