¿Por qué exactamente eval es malo?

Resuelto Jay asked hace 14 años • 0 respuestas

Sé que los programadores de Lisp y Scheme suelen decir que eso evaldebería evitarse a menos que sea estrictamente necesario. He visto la misma recomendación para varios lenguajes de programación, pero aún no he visto una lista de argumentos claros en contra del uso de eval. ¿ Dónde puedo encontrar una descripción de los posibles problemas de uso eval?

Por ejemplo, conozco los problemas de GOTOla programación procedimental (hace que los programas sean ilegibles y difíciles de mantener, hace que los problemas de seguridad sean difíciles de encontrar, etc.), pero nunca he visto los argumentos en contra eval.

Curiosamente, los mismos argumentos en contra GOTOdeberían ser válidos contra las continuaciones, pero veo que los intrigantes, por ejemplo, no dirán que las continuaciones sean "malas"; solo debes tener cuidado al usarlas. Es mucho más probable que desaprueben el uso de código evalque el uso de continuaciones (hasta donde puedo ver, podría estar equivocado).

Jay avatar Apr 03 '10 20:04 Jay
Aceptado

Hay varias razones por las que no se debe utilizar EVAL.

La razón principal para los principiantes es: no lo necesitas.

Ejemplo (asumiendo Common Lisp):

EVALUAR una expresión con diferentes operadores:

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

Eso está mejor escrito como:

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

Hay muchos ejemplos en los que los principiantes que aprenden Lisp creen que necesitan EVAL, pero no lo necesitan, ya que las expresiones se evalúan y también se puede evaluar la parte de la función. La mayoría de las veces el uso de EVALmuestra una falta de comprensión del evaluador.

Es el mismo problema con las macros. A menudo, los principiantes escriben macros, donde deberían escribir funciones, sin comprender para qué sirven realmente las macros y sin comprender que una función ya hace el trabajo.

A menudo es la herramienta incorrecta para el trabajo EVALy a menudo indica que el principiante no comprende las reglas habituales de evaluación de Lisp.

Si cree que lo necesita EVAL, compruebe si se puede utilizar algo como o en su lugar FUNCALL.REDUCEAPPLY

  • FUNCALL- llamar a una función con argumentos:(funcall '+ 1 2 3)
  • REDUCE- llamar a una función en una lista de valores y combinar los resultados:(reduce '+ '(1 2 3))
  • APPLY- llamar a una función con una lista como argumentos: (apply '+ '(1 2 3)).

P: ¿Realmente necesito eval o el compilador/evaluador ya es lo que realmente quiero?

Las principales razones a evitar EVALpara usuarios un poco más avanzados:

  • desea asegurarse de que su código esté compilado, porque el compilador puede verificar el código en busca de muchos problemas y genera código más rápido, a veces MUCHO MUCHO (eso es factor 1000 ;-)) código más rápido

  • El código que se construye y necesita ser evaluado no se puede compilar lo antes posible.

  • La evaluación de entradas arbitrarias del usuario abre problemas de seguridad.

  • Algún uso de la evaluación EVALpuede ocurrir en el momento equivocado y crear problemas de compilación.

Para explicar el último punto con un ejemplo simplificado:

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

Por lo tanto, es posible que desee escribir una macro que, según el primer parámetro, utilice SINo COS.

(foo 3 4)hace (sin 4)y (foo 1 4)hace (cos 4).

Ahora podemos tener:

(foo (+ 2 1) 4)

Esto no da el resultado deseado.

Entonces es posible que desee reparar la macro FOOEVAluando la variable:

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

(foo (+ 2 1) 4)

Pero esto todavía no funciona:

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

El valor de la variable simplemente no se conoce en el momento de la compilación.

Una razón general importante para evitarlo EVAL: a menudo se usa para trucos feos.

Rainer Joswig avatar Apr 03 '2010 14:04 Rainer Joswig

eval(en cualquier idioma) no es malo de la misma manera que una motosierra no es mala. Es una herramienta. Resulta ser una herramienta poderosa que, cuando se usa mal, puede cortar extremidades y destripar (metafóricamente hablando), pero lo mismo puede decirse de muchas herramientas en la caja de herramientas de un programador, incluidas:

  • gotoy amigos
  • subprocesamiento basado en bloqueo
  • continuaciones
  • macros (higiénicas u otras)
  • punteros
  • excepciones reiniciables
  • código automodificable
  • ...y un elenco de miles.

Si tiene que utilizar alguna de estas herramientas poderosas y potencialmente peligrosas, pregúntese tres veces "¿por qué?" en una cadena. Por ejemplo:

"¿Por qué tengo que usar eval?" "Por foo". "¿Por qué es necesario foo?" "Porque ..."

Si llega al final de esa cadena y la herramienta todavía parece ser lo correcto, entonces hágalo. Documente muchísimo. Pruébalo a fondo. Verifique la corrección y la seguridad una y otra vez. Pero hazlo.

JUST MY correct OPINION avatar Apr 03 '2010 14:04 JUST MY correct OPINION

Eval está bien, siempre y cuando sepas EXACTAMENTE lo que implica. Cualquier entrada del usuario DEBE ser verificada y validada y todo. Si no sabes cómo estar 100% seguro, no lo hagas.

Básicamente, un usuario puede escribir cualquier código para el idioma en cuestión y se ejecutará. Puedes imaginarte cuánto daño puede causar.

Tor Valamo avatar Apr 03 '2010 13:04 Tor Valamo

"¿Cuándo debo usar eval?" podría ser una mejor pregunta.

La respuesta corta es "cuando su programa está destinado a escribir otro programa en tiempo de ejecución y luego ejecutarlo". La programación genética es un ejemplo de una situación en la que probablemente tenga sentido utilizarla eval.

Zak avatar Apr 04 '2010 11:04 Zak