In what ways does the following "eval" regularity break?
On Oct 29, 2008, at 11:23 PM, Mark S. Miller wrote:
The intent of ES3's eval operator is clearly that it at least approximate the following result:
For certain triples of source code text: <some code a> <some code b> <some code c> is equivalent to <some code a> eval("<some code b>") <some code c>
By placing quotes around <some code b>, I am not suggesting literally surrounding it with quotes, but rather turning it into a string literal whose value is the original code string.
Certainly, we understand that <some code b> must be balanced and must either be an expression, a statement, a block, or a function body.
Even with these restrictions, there are some cases that don't work:
function foo() {eval('return 3;');} foo(); SyntaxError on line 1: return not in function
var declaration is another thing that is different. Inside eval, var
makes a deletable binding. break also won't work.
- Maciej
This is all intriguingly similar to our previous discussions of Tennent Correspondence (TC), to whit:
The intent of ES3's function abstraction is clearly that it at least approximate lambda abstraction. If it actually provided proper lambda abstraction, we'd have TC (though ES is better than the vast majority of other languages in this regard). By understanding the ways in which ES3's function violates TC, we come to a better understanding of how to use it well, and of what hazards to watch out for. Our discussions on this list have really helped my understanding of function. Likewise, with eval, if we understand better in what ways it violates the regularity it approximates so well, we'll understand better the hazards to watch out for in the occasional uses we encounter.
A case I'm particularly interested in is when <some code b> is the body of a function. Other than the return issue illustrated above, in what other ways does ES3's eval() violate this regularity? One place to look is the difference between the Program production + the notion of eval context on the one hand vs the function body production + the notion of function context on the other hand. In ES3.1, we allow the "use strict" directive only at the beginning of Program units. If one tried to get the effect of turning strictness on for an individual function body by evaling a Program string beginning with "use strict" that otherwise contained the function's original code, performance aside, and other than the above "return" issue, how else might one get into trouble?
In a similar vein, in what ways might
new Function("<some code b>") differ in meaning from function(){eval("<some code b>");}
The obvious one: In the latter, <source code b> can refer to non-global variable that are in scope at eval's site. What else?
For one thing, local variables introduced by <some code b> will not be
deletable in the first case, but will be in the latter case.
Personally I think use of the local-scope eval should be discouraged.
We should introduce an explicit globalEval function which has eval
function rather than eval operator semantics, i.e. evaluates at global
scope. In my experience, programs using eval rarely truly want local
eval, and so they are doing something that defeats lexecial analysis
for no reason. I think we should even consider banning local eval from
strict mode.
, Maciej
On Oct 29, 2008, at 11:23 PM, Mark S. Miller wrote:
The intent of ES3's eval operator is clearly that it at least approximate the following result:
For certain triples of source code text: <some code a> <some code b> <some code c> is equivalent to <some code a> eval("<some code b>") <some code c>
By placing quotes around <some code b>, I am not suggesting literally surrounding it with quotes, but rather turning it into a string literal whose value is the original code string.
Certainly, we understand that <some code b> must be balanced and must either be an expression, a statement, a block, or a function body.
It must be a Program, grammatically:
15.1.2.1 eval (x)
When the eval function is called with one argument x, the following
steps are taken:
- If x is not a string value, return x.
- Parse x as a Program. If the parse fails, throw a SyntaxError
exception (but see also section 16).
A program is not the same as a function body, grammatically:
12.9 The return Statement
Syntax
ReturnStatement :
return [no LineTerminator here] Expressionopt ;
Semantics
An ECMAScript program is considered syntactically incorrect if it
contains a return statement that is not within a FunctionBody.
A case I'm particularly interested in is when <some code b> is the body of a function. Other than the return issue illustrated above, in what other ways does ES3's eval() violate this regularity?
Maciej pointed out the lack of DontDelete in variable object bindings
created when entering an execution context for eval code. This applies
to function and var both!
In a similar vein, in what ways might
new Function("<some code b>") differ in meaning from function(){eval("<some code b>");}
The obvious one: In the latter, <source code b> can refer to non-global variable that are in scope at eval's site. What else?
The return restriction, again. The deletable variable object bindings
issue.
The right thing(tm) I regret not having the time to inject at the
beginning would be quotations to get ASTs from source text, and an
eval that took an AST, not a string.
On Oct 29, 2008, at 11:46 PM, Maciej Stachowiak wrote:
Personally I think use of the local-scope eval should be
discouraged. We should introduce an explicit globalEval function
which has eval function rather than eval operator semantics, i.e.
evaluates at global scope. In my experience, programs using eval
rarely truly want local eval,
SunSpider has some evals that absolutely want their caller's scope.
and so they are doing something that defeats lexecial analysis for
no reason.
There are lots of dumb eval uses, but I do not agree that most eval
calls could be global-eval. The EXT Ajax library among many others
uses local eval to compile optimized selector-matching functions, e.g.
IIRC gmail uses local eval (and global).
I think we should even consider banning local eval from strict mode.
In light of the examples I gave above, and more that are pretty easy
to find, I think this would make strict mode unused in practice.
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
FWIW, a little empirical data:
I think we should even consider banning local eval from strict mode.
In light of the examples I gave above, and more that are pretty easy to find, I think this would make strict mode unused in practice.
In Dojo, eval is used with no need for local scope about 20 times, and about 3 times needing local scope. Interestingly enough all three times eval used local scope, it was in code that I have written (and I have written a pretty small percentage of Dojo)... I could have missed other cases where eval needed local scope, but it looked all the other cases just really wanted global scope. The 3 cases certainly benefited from local scope, and I could describe them if desired. It would be possible to rewrite the code to not use local scope in the eval, but it would be a pain. Kris -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - enigmail.mozdev.org
iEYEARECAAYFAkkJuU4ACgkQ9VpNnHc4zAwxZQCgvZevkHtLgiIxUxcGp7Qz9lGA DLMAn1UuD2NOIBU1rtYjKfs5oMkmmoJc =rkn/ -----END PGP SIGNATURE-----
Why not introdouce one localEval that evaluates in local scope but does not allow modifying the local scope, a globalEval that evaluates in the global scope, and maybe an expressionEval which allows anonymous function literals and parses { as the beginning of an object literal instead of a block statement?
That should cover current usage of eval except for the case of wanting to inject variables into the scope. Which would mean dropping eval in strict mode isn't that awful an idea.
I don't see the point in adding new functions (global functions,
presumably), at least not without opt-in (which will make such
additions even less usable). JSON is not out of the woods as a
breaking change in ES3.1. ES3.1 otherwise tries to put new properties
in Object to avoid dancing with object-detecting scripts that
conditionally supply their own JSON, localEval or whatever.
JS programmers have better best-practices guides now. Stupid eval
tricks remain but the ones I see are in old code. Browser intersection
semantics make indirect eval global, otherWindow.eval scope to a
different global, and eval called as an "operator" (with parentheses
around its argument, of course) local in context. Changing this is
going to be hard, possibly harder than injecting new names into the
global object.
Between a rock and a hard place the least we should do (i.e., what
fits in 3.1) is to go straight ahead: specify indirect, other-global,
and operator eval. The wiki has discussion and draft spec language
from ES4.
2008/10/30 Brendan Eich <brendan at mozilla.com>:
On Oct 29, 2008, at 11:46 PM, Maciej Stachowiak wrote:
Personally I think use of the local-scope eval should be discouraged. We should introduce an explicit globalEval function which has eval function rather than eval operator semantics, i.e. evaluates at global scope. In my experience, programs using eval rarely truly want local eval,
SunSpider has some evals that absolutely want their caller's scope.
and so they are doing something that defeats lexecial analysis for no reason.
There are lots of dumb eval uses, but I do not agree that most eval calls could be global-eval. The EXT Ajax library among many others uses local eval to compile optimized selector-matching functions, e.g. IIRC gmail uses local eval (and global).
We use global eval for dynamic loading of code.
We also use eval in a few places to turn responses loaded from the server as text into object structures. These should all be replaceable with JSON.parse.
I often find myself wanting an eval without side effects (except for the return value of course). Having this would allow the js engines to not have to go into slow mode when they see an eval.
On Thu, Oct 30, 2008 at 8:35 AM, Brendan Eich <brendan at mozilla.com> wrote:
[...] Browser intersection semantics make indirect eval global, [...]
I had hoped so. This came up at Redmond, and unfortunately, without either you or Lars there, I was unable to reconstruct why we thought it would be upwards compatible to make indirect eval global. The specification of indirect eval was also discussed in this morning's ES3.1 phone call. Based on the ES3 spec and a quick testing of the browsers, as well as the memory of those who had an opinion about this in Redmond, we've been proceeding with the assumption that the ES3 spec should be read as:
An implementation may implement an indirect eval either by throwing an EvalError or by treating it as equivalent to the eval operator.
Testing on FF3.0.3 and FF3.1Beta, with and without TraceMonkey enabled, seemed to bear this out:
function foo(a, b, c) { return b(c); }
foo(3, eval, 'a'); // yields 3
foo(3, window.eval, 'a'); // yields 3
However, a bit more testing reveals something truly bizarre:
window.a = 'x';
foo(3, window.eval, 'a') // yields 'x'
foo(3, eval, 'a'); // yields 'x'
I can't think of any semantics that would account for both behaviors. Is this a bug?
On Oct 30, 2008, at 10:20 AM, Mark S. Miller wrote:
On Thu, Oct 30, 2008 at 8:35 AM, Brendan Eich <brendan at mozilla.com>
wrote:[...] Browser intersection semantics make indirect eval global, [...]
I had hoped so. This came up at Redmond, and unfortunately, without either you or Lars there, I was unable to reconstruct why we thought it would be upwards compatible to make indirect eval global. The specification of indirect eval was also discussed in this morning's ES3.1 phone call. Based on the ES3 spec and a quick testing of the browsers, as well as the memory of those who had an opinion about this in Redmond, we've been proceeding with the assumption that the ES3 spec should be read as:
An implementation may implement an indirect eval either by throwing an EvalError or by treating it as equivalent to the eval operator.
Testing on FF3.0.3 and FF3.1Beta, with and without TraceMonkey enabled, seemed to bear this out:
function foo(a, b, c) { return b(c); } foo(3, eval, 'a'); // yields 3 foo(3, window.eval, 'a'); // yields 3
However, a bit more testing reveals something truly bizarre:
window.a = 'x'; foo(3, window.eval, 'a') // yields 'x' foo(3, eval, 'a'); // yields 'x'
I can't think of any semantics that would account for both behaviors. Is this a bug?
In recent WebKit versions, this test prints PASS twice:
<pre><script>
var a = "PASS"; function foo(a, b, c) { return b(c); } document.writeln(foo(3, eval, 'a')); document.writeln(foo(3, window.eval, 'a')); </script></pre>
(prints nothing if you remove the to-level var a declaration).
Opera matches this behavior.
In a recent Firefox nightly it also prints PASS twice, but FAIL twice
if you remove the top-level declaration. That seems in line with your
results above. I agree that is puzzling.
On Thu, Oct 30, 2008 at 11:00 AM, Maciej Stachowiak <mjs at apple.com> wrote:
In recent WebKit versions, this test prints PASS twice:
<pre><script> var a = "PASS"; function foo(a, b, c) { return b(c); } document.writeln(foo(3, eval, 'a')); document.writeln(foo(3, window.eval, 'a')); </script></pre>
(prints nothing if you remove the to-level var a declaration).
Opera matches this behavior.
In a recent Firefox nightly it also prints PASS twice, but FAIL twice if you remove the top-level declaration. That seems in line with your results above. I agree that is puzzling.
What's FAIL?
On Oct 30, 2008, at 11:12 AM, Mark S. Miller wrote:
On Thu, Oct 30, 2008 at 11:00 AM, Maciej Stachowiak <mjs at apple.com>
wrote:In recent WebKit versions, this test prints PASS twice:
<pre><script> var a = "PASS"; function foo(a, b, c) { return b(c); } document.writeln(foo(3, eval, 'a')); document.writeln(foo(3, window.eval, 'a')); </script></pre>
(prints nothing if you remove the to-level var a declaration).
Opera matches this behavior.
In a recent Firefox nightly it also prints PASS twice, but FAIL
twice if you remove the top-level declaration. That seems in line with your
results above. I agree that is puzzling.What's FAIL?
Oops, I edited the test case after running it, I had 3 replaced with
"FAIL". (I wanted to see if your original 3 did anything different
than the string "FAIL", which of course it does not.) The correct
version:
<pre><script>
var a = "PASS"; function foo(a, b, c) { return b(c); } document.writeln(foo("FAIL", eval, 'a')); document.writeln(foo("FAIL", window.eval, 'a')); </script></pre>
On Oct 30, 2008, at 10:20 AM, Mark S. Miller wrote:
On Thu, Oct 30, 2008 at 8:35 AM, Brendan Eich <brendan at mozilla.com>
wrote:[...] Browser intersection semantics make indirect eval global, [...]
I had hoped so. This came up at Redmond, and unfortunately, without either you or Lars there, I was unable to reconstruct why we thought it would be upwards compatible to make indirect eval global.
Probably when we started, we had the Firefox 1.0-1.5 behavior
(JS1.5-1.6) in mind. Since then, elves "fixed" bugs. :-/
Still I do not know of web content that calls indirect eval and
expects local eval. Gmail did (and may still) due to its cruncher do
something like
var Ae = eval;... Ae(s)
but the program in string s wanted only global scope.
The specification of indirect eval was also discussed in this morning's ES3.1 phone call. Based on the ES3 spec and a quick testing of the browsers, as well as the memory of those who had an opinion about this in Redmond, we've been proceeding with the assumption that the ES3 spec should be read as:
An implementation may implement an indirect eval either by throwing an EvalError or by treating it as equivalent to the eval operator.
This is not what we want, either as implementors or JS users.
Implementors in particular have to deoptimize at runtime based on the
eval built-in being invoked by some random name, in an environment
that the compiler optimized assuming no eval call. Users cannot easily
reason about hidden eval calls.
Testing on FF3.0.3 and FF3.1Beta, with and without TraceMonkey enabled, seemed to bear this out:
function foo(a, b, c) { return b(c); } foo(3, eval, 'a'); // yields 3 foo(3, window.eval, 'a'); // yields 3
Try Firefox 1 or 1.5. (Damn elves.... :-)
BTW, did you test V8?
However, a bit more testing reveals something truly bizarre:
window.a = 'x'; foo(3, window.eval, 'a') // yields 'x' foo(3, eval, 'a'); // yields 'x'
I can't think of any semantics that would account for both behaviors. Is this a bug?
No, it is ancient pre-ECMA magic. The indirect case where eval was
referenced from the global (window) object adds an implicit with
(window). So
return b(c);
becomes
with (window) return eval('a');
We've kept compatibility here for over a decade, but we're more than
willing to break it for a standard that says how indirect eval should
work.
On Oct 30, 2008, at 12:24 PM, Brendan Eich wrote:
On Oct 30, 2008, at 10:20 AM, Mark S. Miller wrote:
On Thu, Oct 30, 2008 at 8:35 AM, Brendan Eich <brendan at mozilla.com>
wrote:[...] Browser intersection semantics make indirect eval global,
[...]I had hoped so. This came up at Redmond, and unfortunately, without either you or Lars there, I was unable to reconstruct why we thought it would be upwards compatible to make indirect eval global.
Probably when we started, we had the Firefox 1.0-1.5 behavior
(JS1.5-1.6) in mind. Since then, elves "fixed" bugs. :-/Still I do not know of web content that calls indirect eval and
expects local eval. Gmail did (and may still) due to its cruncher do
something likevar Ae = eval;... Ae(s)
but the program in string s wanted only global scope.
We have not found compatibility issues since we converted indirect
eval to global eval in WebKit. (We have about 10,000 regular nightly
users so it's had some test coverage, but that is still a fair bit
less than a public beta or a full release version.) I believe what we
have now matches the old proposed ES4 behavior.
Brendan, do you know if the Mozilla change on this was for reasons of
Web compatibility?
, Maciej
On Oct 30, 2008, at 12:58 PM, Maciej Stachowiak wrote:
On Oct 30, 2008, at 12:24 PM, Brendan Eich wrote:
Probably when we started, we had the Firefox 1.0-1.5 behavior
(JS1.5-1.6) in mind. Since then, elves "fixed" bugs. :-/Still I do not know of web content that calls indirect eval and
expects local eval. Gmail did (and may still) due to its cruncher
do something likevar Ae = eval;... Ae(s)
but the program in string s wanted only global scope.
We have not found compatibility issues since we converted indirect
eval to global eval in WebKit. (We have about 10,000 regular nightly
users so it's had some test coverage, but that is still a fair bit
less than a public beta or a full release version.) I believe what
we have now matches the old proposed ES4 behavior.Brendan, do you know if the Mozilla change on this was for reasons
of Web compatibility?
Not exactly. I believe the change was an unintended consequence of
fixing a series of bugs that did not explicitly request that indirect
eval be local. These bugs involved, e.g. Prototype (the JS library)
and its Ajax.Updater (with evalScripts set to true). The code in
question used Prototype's forEach. A javascript: URL reduction:
javascript: (function xxx(){ ["var x"].forEach(eval); })();
As I wrote in another post today, we would gladly go back to the
JS1.5-1.6-era indirect-eval-is-global behavior if it were
standardized. We would not be glad about any standard that required
indirect eval to be "operator eval". No doubt you feel the same way!
On Oct 30, 2008, at 1:09 PM, Brendan Eich wrote:
On Oct 30, 2008, at 12:58 PM, Maciej Stachowiak wrote:
On Oct 30, 2008, at 12:24 PM, Brendan Eich wrote:
Probably when we started, we had the Firefox 1.0-1.5 behavior
(JS1.5-1.6) in mind. Since then, elves "fixed" bugs. :-/Still I do not know of web content that calls indirect eval and
expects local eval. Gmail did (and may still) due to its cruncher
do something likevar Ae = eval;... Ae(s)
but the program in string s wanted only global scope.
We have not found compatibility issues since we converted indirect
eval to global eval in WebKit. (We have about 10,000 regular
nightly users so it's had some test coverage, but that is still a
fair bit less than a public beta or a full release version.) I
believe what we have now matches the old proposed ES4 behavior.Brendan, do you know if the Mozilla change on this was for reasons
of Web compatibility?Not exactly. I believe the change was an unintended consequence of
fixing a series of bugs that did not explicitly request that
indirect eval be local. These bugs involved, e.g. Prototype (the JS
library) and its Ajax.Updater (with evalScripts set to true). The
code in question used Prototype's forEach. A javascript: URL
reduction:javascript: (function xxx(){ ["var x"].forEach(eval); })();
What's the expected behavior for this reduction?
As I wrote in another post today, we would gladly go back to the
JS1.5-1.6-era indirect-eval-is-global behavior if it were
standardized. We would not be glad about any standard that required
indirect eval to be "operator eval". No doubt you feel the same way!
Yes, we would prefer that the standard require indirect eval to be
global, and would not like the standard require it to be local.
The reason I asked about the change in Mozilla behavior was to see if
we had evidence of this behavior not being Web-compatible; but it
seems not.
, Maciej
On Oct 30, 2008, at 1:09 PM, Brendan Eich wrote:
These bugs involved, e.g. Prototype (the JS library) and its
Ajax.Updater (with evalScripts set to true). The code in question
used Prototype's forEach. A javascript: URL reduction:javascript: (function xxx(){ ["var x"].forEach(eval); })();
Prototype 1.5.1.1 (and older, I think we suggested this as a
workaround) has
evalScripts: function() {
return this.extractScripts().map(function(script) { return
eval(script) });
},
No indirect eval called from map, but the operator eval here does not
depend on its environment at all (it can't, since neither function in
which it nests has any formal parameters or other local bindings). It
could be optimized nicely in ES1-3.
On Oct 30, 2008, at 1:27 PM, Brendan Eich wrote:
On Oct 30, 2008, at 1:09 PM, Brendan Eich wrote:
These bugs involved, e.g. Prototype (the JS library) and its
Ajax.Updater (with evalScripts set to true). The code in question
used Prototype's forEach. A javascript: URL reduction:javascript: (function xxx(){ ["var x"].forEach(eval); })();
Prototype 1.5.1.1 (and older, I think we suggested this as a
workaround) hasevalScripts: function() { return this.extractScripts().map(function(script) { return
eval(script) }); },No indirect eval called from map, but the operator eval here does
not depend on its environment at all (it can't, since neither
function in which it nests has any formal parameters or other local
bindings). It could be optimized nicely in ES1-3.
Sure, what I am wondering is whether the var declaration you had above
is expected to be a local or global binding (or if the script doesn't
care).
, Maciej
Mark S. Miller wrote:
In a similar vein, in what ways might
new Function("<some code b>")
differ in meaning from function(){eval("<some code b>");}
The obvious one: In the latter, <source code b> can refer to non-global variable that are in scope at eval's site. What else?
Note that those variables at eval's call site might include some that shadow global bindings, including Array, Object, etc. Either the global or the shadowing versions of those bindings might not be the original ones.
Another, non-semantic but nevertheless quite important, difference is efficiency: a function created by 'new Function' will typically hold an intermediate or compiled form of the function code that is not recomputed if the function is reused.
(Ideally the underlying primitive should be 'compile(code, n)' where n is a hint to the number of times the code is likely to be called.)
On Oct 30, 2008, at 1:24 PM, Maciej Stachowiak wrote:
The reason I asked about the change in Mozilla behavior was to see
if we had evidence of this behavior not being Web-compatible; but it
seems not.
Definitely not. Having now done the CVS archeology and read the bugs,
it was all a case of fixing bugs in indirect eval without intending to
make it local, where the fixes had the consequence of making it local.
On Oct 30, 2008, at 1:32 PM, Maciej Stachowiak wrote:
Sure, what I am wondering is whether the var declaration you had
above is expected to be a local or global binding (or if the script
doesn't care).
As far as I can tell (Prototype folks on this list, please help here),
this is all synthetic test-fodder. The test scripts do not want a
local var binding. On the other hand, anyone evaluating
(function xxx(){ ["var x"].forEach(eval); })();
would get a global var x, which should be the specified outcome, but
which is probably a mistake on the programmer's part outside of test
code.
On Oct 30, 2008, at 22:28 , Brendan Eich wrote:
As far as I can tell (Prototype folks on this list, please help
here), this is all synthetic test-fodder. The test scripts do not
want a local var binding.
I'm not sure what you mean by synthetic test-fodder in that case. The
function which Maciej mentions is mainly used to evaluate the content
of script tags contained in an HTML snippet returned by an ajax
request. Although it's rare to need to define variables in that
context, the behaviour expected by users when they do so is for those
variables to live in the global scope.
On the other hand, anyone evaluating
(function xxx(){ ["var x"].forEach(eval); })();
would get a global var x, which should be the specified outcome,
but which is probably a mistake on the programmer's part outside of
test code.
Agreed.
Best,
Tobie
On Nov 2, 2008, at 3:22 PM, Tobie Langel wrote:
On Oct 30, 2008, at 22:28 , Brendan Eich wrote:
As far as I can tell (Prototype folks on this list, please help
here), this is all synthetic test-fodder. The test scripts do not
want a local var binding.I'm not sure what you mean by synthetic test-fodder in that case.
eval-created var bindings.
The function which Maciej mentions is mainly used to evaluate the
content of script tags contained in an HTML snippet returned by an
ajax request. Although it's rare to need to define variables in that
context, the behaviour expected by users when they do so is for
those variables to live in the global scope.
Good to hear.
On the other hand, anyone evaluating
(function xxx(){ ["var x"].forEach(eval); })();
would get a global var x, which should be the specified outcome,
but which is probably a mistake on the programmer's part outside of
test code.Agreed.
Best,
Thanks,
On Nov 2, 2008, at 3:22 PM, Tobie Langel wrote:
On Oct 30, 2008, at 22:28 , Brendan Eich wrote:
As far as I can tell (Prototype folks on this list, please help
here), this is all synthetic test-fodder. The test scripts do not
want a local var binding.I'm not sure what you mean by synthetic test-fodder in that case.
The function which Maciej mentions is mainly used to evaluate the
content of script tags contained in an HTML snippet returned by an
ajax request. Although it's rare to need to define variables in that
context, the behaviour expected by users when they do so is for
those variables to live in the global scope.
Good to hear this confirmed -- it was not clear from the Mozilla CVS
and bugzilla histories.
On the other hand, anyone evaluating
(function xxx(){ ["var x"].forEach(eval); })();
would get a global var x, which should be the specified outcome,
but which is probably a mistake on the programmer's part outside of
test code.Agreed.
Thanks,
The intent of ES3's eval operator is clearly that it at least approximate the following result:
For certain triples of source code text: <some code a> <some code b> <some code c>
is equivalent to <some code a> eval("<some code b>") <some code c>
By placing quotes around <some code b>, I am not suggesting literally
surrounding it with quotes, but rather turning it into a string literal whose value is the original code string.
Certainly, we understand that <some code b> must be balanced and must
either be an expression, a statement, a block, or a function body.
Even with these restrictions, there are some cases that don't work:
This is all intriguingly similar to our previous discussions of Tennent Correspondence (TC), to whit:
The intent of ES3's function abstraction is clearly that it at least approximate lambda abstraction. If it actually provided proper lambda abstraction, we'd have TC (though ES is better than the vast majority of other languages in this regard). By understanding the ways in which ES3's function violates TC, we come to a better understanding of how to use it well, and of what hazards to watch out for. Our discussions on this list have really helped my understanding of function. Likewise, with eval, if we understand better in what ways it violates the regularity it approximates so well, we'll understand better the hazards to watch out for in the occasional uses we encounter.
A case I'm particularly interested in is when <some code b> is the
body of a function. Other than the return issue illustrated above, in what other ways does ES3's eval() violate this regularity? One place to look is the difference between the Program production + the notion of eval context on the one hand vs the function body production + the notion of function context on the other hand. In ES3.1, we allow the "use strict" directive only at the beginning of Program units. If one tried to get the effect of turning strictness on for an individual function body by evaling a Program string beginning with "use strict" that otherwise contained the function's original code, performance aside, and other than the above "return" issue, how else might one get into trouble?
In a similar vein, in what ways might
differ in meaning from function(){eval("<some code b>");}
The obvious one: In the latter, <source code b> can refer to
non-global variable that are in scope at eval's site. What else?