eval-introduced bindings do not have the DontDelete property set on them, according to the post-hoc language semantics, so unlike proper lexical variables, they may be deleted.

when is eval really eval?

Imagine you are trying to analyze some JavaScript code. If you see eval(...), is it really eval?

Not necessarily.

eval pretends to be a regular, mutable binding, so it can be rebound:

> eval = print
> eval('foo')
foo // printed

or, shadowed lexically:

> function () { var eval = print; eval('foo'); }
foo // printed

or, shadowed dynamically:

> with({'eval': print}) { eval('foo'); }
foo // printed

You would think that if you can somehow freeze the eval binding on the global object, and verify that there are no with forms, and no statements of the form var eval = ..., that you could guarantee that eval is eval, but that is not the case:

An engine still has to check at run-time that eval is really eval. This crazy behavior will be with us as long as classic mode, which is to say, forever.

Strict-mode eval does have the one saving grace that it cannot introduce lexical bindings, so implementors do get a break there, but it's a poor consolation prize.

in summary

What can an engine do when it sees eval?

Not much. It can't even prove that it is actually eval unless eval is not bound lexically, there is no with, there is no intervening non-strict call to any identifier eval (regardless of whether it is eval or not), and the global object's eval property is bound to the blessed eval function, and is configured as DontDelete and ReadOnly (not the default in web browsers).

But the very fact that an engine sees a call to an identifier eval poisons optimization: because eval can introduce variables, the scope of free variables is no longer lexically apparent, in many cases.

I'll say it again: crazy!!!

17 responses

I took a slightly different tack in my own argument for people to not use eval, in that I specifically focused on the optimizations it disabled. This was in the context of a post discussing implementation of proper strict mode variable binding in eval'd code. Nonetheless, we are in agreement that eval is insane, and no one should use it.

This post is the perfect example of why I never know if I should love or hate the browser guys - on the one hand they invent something like eval(), on the other hand they make extra sure that links in their blog comments are properly linkified. ;)

The behavior you're seeing when you assign `eval` to a variable and execute it is defined by ES5. Indirect calls to `eval` like `var a = eval; a(code)` or `(0, eval)(code)` or `window.eval(code)` are treated as a global evals.http://es5.github.com/#x10.4.2

Juriy Zaytsev (@kangax) has a post on global eval:http://perfectionkills.com/global-eval-what-are-the-options/

and another post examining the `delete` operator and `eval`:http://perfectionkills.com/understanding-delete/#deleting_variables_via_eval

I'm inclined to agree with Zachary: there's no good reason to use eval. Quite apart from the performance impacts, using it can potentially expose your users to malicious code. Thankfully, browsers have given us there is now another way to parse JSON, but there are still plenty of js "ninjas" out there who think that cleaver uses of eval are a means of demsonstrating their coding prowess.

Andy, my question to you as a scheme programmer, and language implementer, is whether you think there is a good case for including eval or something similar into the language.

I took a marginally distinctive tack in my own particular contention for individuals to not utilize eval, in that I particularly centered around the enhancements it debilitated. This was with regards to a post talking about usage of legitimate strict mode variable official in eval'd code. The conduct you're seeing when you appoint `eval` to a variable and execute it is characterized by ES5.