Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

clojure - Why exactly is eval evil?

I know that Lisp and Scheme programmers usually say that eval should be avoided unless strictly necessary. I’ve seen the same recommendation for several programming languages, but I’ve not yet seen a list of clear arguments against the use of eval. Where can I find an account of the potential problems of using eval?

For example, I know the problems of GOTO in procedural programming (makes programs unreadable and hard to maintain, makes security problems hard to find, etc), but I’ve never seen the arguments against eval.

Interestingly, the same arguments against GOTO should be valid against continuations, but I see that Schemers, for example, won’t say that continuations are "evil" -- you should just be careful when using them. They’re much more likely to frown upon code using eval than upon code using continuations (as far as I can see -- I could be wrong).

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There are several reasons why one should not use EVAL.

The main reason for beginners is: you don't need it.

Example (assuming Common Lisp):

EVALuate an expression with different operators:

(let ((ops '(+ *)))
  (dolist (op ops)
    (print (eval (list op 1 2 3)))))

That's better written as:

(let ((ops '(+ *)))
  (dolist (op ops)
    (print (funcall op 1 2 3))))

There are lots of examples where beginners learning Lisp think they need EVAL, but they don't need it - since expressions are evaluated and one can also evaluate the function part. Most of the time the use of EVAL shows a lack of understanding of the evaluator.

It is the same problem with macros. Often beginners write macros, where they should write functions - not understanding what macros are really for and not understanding that a function already does the job.

It often is the wrong tool for the job to use EVAL and it often indicates that the beginner does not understand the usual Lisp evaluation rules.

If you think you need EVAL, then check if something like FUNCALL, REDUCE or APPLY could be used instead.

  • FUNCALL - call a function with arguments: (funcall '+ 1 2 3)
  • REDUCE - call a function on a list of values and combine the results: (reduce '+ '(1 2 3))
  • APPLY - call a function with a list as the arguments: (apply '+ '(1 2 3)).

Q: do I really need eval or does the compiler/evaluator already what I really want?

The main reasons to avoid EVAL for slightly more advanced users:

  • you want to make sure that your code is compiled, because the compiler can check code for many problems and generates faster code, sometimes MUCH MUCH MUCH (that's factor 1000 ;-) )faster code

  • code that's constructed and needs to be evaluated can't be compiled as early as possible.

  • eval of arbitrary user input opens up security problems

  • some use of evaluation with EVAL can happen at the wrong time and create build problems

To explain the last point with a simplified example:

(defmacro foo (a b)
  (list (if (eql a 3) 'sin 'cos) b))

So, I may want to write a macro that based on the first parameter uses either SIN or COS.

(foo 3 4) does (sin 4) and (foo 1 4) does (cos 4).

Now we may have:

(foo (+ 2 1) 4)

This does not give the desired result.

One then may want to repair the macro FOO by EVALuating the variable:

(defmacro foo (a b)
  (list (if (eql (eval a) 3) 'sin 'cos) b))

(foo (+ 2 1) 4)

But then this still does not work:

(defun bar (a b)
  (foo a b))

The value of the variable is just not known at compile time.

A general important reason to avoid EVAL: it is often used for ugly hacks.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...