
On eval in dynamic languages generally and in Racket specifically (2011) - soegaard
http://blog.racket-lang.org/2011/10/on-eval-in-dynamic-languages-generally.html
======
AlexanderDhoore
Lisp is probably the only language where eval makes sense. If you need to
concatenate strings together to create "code", you're doing it wrong.

~~~
icebraining
What you mean is that it only makes sense in homoiconic languages; Lisp is not
the only one[1]. In particular, there's Julia, now[2].

[1]
[http://en.wikipedia.org/wiki/Homoiconicity#Examples](http://en.wikipedia.org/wiki/Homoiconicity#Examples)

[2]
[http://docs.julialang.org/en/latest/manual/metaprogramming/](http://docs.julialang.org/en/latest/manual/metaprogramming/)

~~~
kazinator
That reminds me of the ancient Infix module for Common Lisp.

    
    
        [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...](http://www.cs.cmu.edu/afs/cs/project/ai-
repository/ai/lang/lisp/code/syntax/infix/infix.cl)

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.

~~~
innguest
For adding infix to s-exps, "sweet expressions" are a much cleaner approach:
[http://www.dwheeler.com/readable/](http://www.dwheeler.com/readable/)

~~~
kazinator
I'm sure I've seen that before. Anyway, it's destined for the same dustbin as
infix.cl. These things have value in showing "see, you can do this, but Lisp
programmers don't actually use it". Before infix.cl and Readable, back in the
1970's, there was also something called CGOL[1]. This was described in a 1976
MIT paper by Pratt R. Vaughan titled _CGOL: An Alternative External
Representation for LISP Users_.

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.

[1] [http://en.wikipedia.org/wiki/CGOL](http://en.wikipedia.org/wiki/CGOL)

------
joe_the_user
I think I can argue that a raw "eval" is always going to be the worst way to
achieve a given result.

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.

~~~
vidarh
It's not just the danger. In sufficiently dynamic languages, it wreaks havoc
on optimization unless you're prepared to essentially re-jit the entire code.

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.

------
anon4
One case I know of where eval is used extensively is Python's namedtuple
function from the collections module. It generates a class that behaves like a
tuple, except the positions are named, so kind of like a read-only struct.
Python has the __slots__ facility for exactly this situation - when you know
exactly how many members your instances will have and don't want
extensibility, but when namedtuple was written, it wasn't possible to
programatically generate a class body with __slots__ in any way other than to
generate the source for it and call eval. So here we are.

~~~
kazinator
Indeed, some things can't be done unless you use eval; but some of those
things just need something much less than eval added to the language and then
they can be done.

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.

~~~
GregBuchholz

        ;;; 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...](http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Body/convar_call-
a_uments-limit.html)

------
anaphor
eval is not a good idea if you want to write a compiler that generates small
efficient binaries either. This is why, for example the Stalin Scheme compiler
does not include eval.

"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."

[https://github.com/barak/stalin](https://github.com/barak/stalin)

~~~
abecedarius
That's worth bringing up, but it's not eval that causes a problem, it's access
to environments, especially mutable access. You can implement eval as an
interpreter in your own Scheme program, so supplying it as primitive can have
no extra consequences; conversely if you have first-class environments,
passing (the-environment) to some opaque procedure would do all the damage to
analyzability already.

------
saberworks
Please don't consider every usage of the term "eval" to be what is discussed
in this article. Perl has two forms of eval, one which takes a string and
executes it as code (the "bad" one) and one which takes a block of code (used
for exception handling) which is parsed only once (essentially at compile
time).

[http://perldoc.perl.org/functions/eval.html](http://perldoc.perl.org/functions/eval.html)

