On eval in dynamic languages generally and in Racket specifically (2011)
blog.racket-lang.org
blog.racket-lang.org
[1] http://en.wikipedia.org/wiki/Homoiconicity#Examples
[2] http://docs.julialang.org/en/latest/manual/metaprogramming/
[1]> (load "infix")
T
[2]> (let ((a 1) (b 2) (c 3)) #i(a*b+c))
5
[3]> '#i(a*b+c)
(+ (* A B) C)
Like the colon in Julia, we can quote the infix (#i) expression, to reveal its AST.Infix URL:
http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/l...
Infix has f(x,y) type function calls and a[i,j] type array referencing and whatnot.
It's not really homoiconicity because the AST doesn't resemble the language being quoted. The AST and its printed notation are homoiconic; the LALR(1) statement/expression/infix cruft layered on it arguably isn't.
And, of course, Lisp wasn't supposed to wear its S-expression underwear on the outside in the first place; M-expressions were supposed to be used for programming.
Since eval calls the entire system to do something, it involves every possible danger that programming the system ordinarily involves and it involves dangers particular to it (not being able to directly check the syntax any of the code beforehand, constructing values with strings, the possibility the scope of variable-binding may vary from call to call, etc). The danger is inherent in the approach.
This isn't a reason to never use eval, just a reason to never use it if you can think of an alternative. Sometimes you can't find an alternative in the time allotted.
And if you use eval or any equivalent, just remember you have opened a bottomless can of worms. We have spent generations now cleaning up SQL injections, for example.
Ruby for example - if you enter eval() with a string, you may exit it to find that even basic stuff like adding two integers together has changed (and may suddenly have side effects), so any work you've done to inline (or cache) fast paths may suddenly have been undone. It's not likely that the worst changes will have happened, but they may, and so unless the string is constant and you can analyse it upfront, you need to be prepared for them unless you want to restrict yourself to a subset of the language.
Case in point: if you don't have apply in Lisp, how do you take a list, and turn it into the arguments of a function call?
The ability to do this is actually represents a modicum of introspection, but far short of a full blown eval.
;;; The Daily WTF to the rescue, no eval or introspection needed
(defun my-apply (f lst)
(case (length lst)
(0 (funcall f))
(1 (funcall f (nth 0 lst)))
(2 (funcall f (nth 0 lst) (nth 1 lst)))
(3 (funcall f (nth 0 lst) (nth 1 lst) (nth 2 lst)))
(t 'YouNeedToExtendThisInTheObviousWay)))
...IIRC Common Lisp allows your implementation to limit the number of arguments a function can take.http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec...
"Running that image has equivalent semantics to loading the Scheme source file into a virgin Scheme interpreter and then terminating its execution. The chief limitation is that it is not possible to LOAD or EVAL new expressions or procedure definitions into a running program after compilation. In return for this limitation, Stalin does substantial global compile-time analysis of the source program under this closed-world assumption and produces executable images that are small, stand-alone, and fast."