Sé que los programadores de Lisp y Scheme suelen decir que se eval
debe evitar 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 cuenta de los posibles problemas de uso eval
?
Por ejemplo, conozco los problemas de la GOTO
programación de procedimientos (hace que los programas sean ilegibles y difíciles de mantener, 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 GOTO
deberían ser válidos en contra de las continuaciones, pero veo que Schemers, por ejemplo, no dirá que las continuaciones son "malvadas" - solo debes tener cuidado al usarlas. Es mucho más probable que frunzan el ceño al usar código eval
que con el uso de continuaciones (por lo que puedo ver, podría estar equivocado).
Respuestas:
Hay varias razones por las cuales uno no debe usar
EVAL
.La razón principal para los principiantes es: no lo necesitas.
Ejemplo (suponiendo Common Lisp):
EVALUAR una expresión con diferentes operadores:
Eso está mejor escrito como:
Hay muchos ejemplos en los que los principiantes que aprenden Lisp piensan 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 deEVAL
muestra una falta de comprensión del evaluador.Es el mismo problema con las macros. A menudo, los principiantes escriben macros, donde deben escribir funciones, sin entender para qué son realmente las macros y sin entender que una función ya hace el trabajo.
A menudo es la herramienta incorrecta para el trabajo
EVAL
y a menudo indica que el principiante no comprende las reglas habituales de evaluación de Lisp.Si cree que lo necesita
EVAL
, verifique si algo comoFUNCALL
,REDUCE
oAPPLY
podría usarse en su lugar.FUNCALL
- llamar a una función con argumentos:(funcall '+ 1 2 3)
REDUCE
- llame a una función en una lista de valores y combine los resultados:(reduce '+ '(1 2 3))
APPLY
- llamar a una función con una lista como los argumentos:(apply '+ '(1 2 3))
.P: ¿realmente necesito evaluar o el compilador / evaluador ya es lo que realmente quiero?
Las principales razones a evitar
EVAL
para 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 (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 la entrada arbitraria del usuario abre problemas de seguridad
cierto uso de la evaluación
EVAL
puede ocurrir en el momento equivocado y crear problemas de compilaciónPara explicar el último punto con un ejemplo simplificado:
Por lo tanto, es posible que desee escribir una macro que, según el primer parámetro, use
SIN
oCOS
.(foo 3 4)
hace(sin 4)
y(foo 1 4)
hace(cos 4)
.Ahora podemos tener:
Esto no da el resultado deseado.
Entonces, uno puede querer reparar la macro
FOO
EVALUANDO la variable:Pero esto todavía no funciona:
El valor de la variable simplemente no se conoce en tiempo de compilación.
Una razón general importante para evitar
EVAL
: a menudo se usa para hacks feos.fuente
eval
simplemente porque no saben que hay un idioma específico o una función de biblioteca para hacer lo que quieren hacer. Ejemplo similar de JS: Quiero obtener una propiedad de un objeto usando un nombre dinámico, así que escribo:eval("obj.+" + propName)
cuando podría haber escritoobj[propName]
."obj.+"
:? Lo último que verifiqué,+
no es válido cuando se usan referencias de punto en JS.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 incorrectamente, puede cortar extremidades y eviscerar (hablando metafóricamente), pero lo mismo puede decirse de muchas herramientas en la caja de herramientas de un programador, que incluyen:goto
y amigosSi tiene que usar alguna de estas herramientas poderosas y potencialmente peligrosas, pregúntese tres veces "¿por qué?" en una cadena Por ejemplo:
Si llegas al final de esa cadena y la herramienta todavía parece que es lo correcto, entonces hazlo. Documente el infierno fuera de él. Pon a prueba el infierno. Vuelva a verificar la corrección y seguridad una y otra vez. Pero hazlo.
fuente
Eval está bien, siempre y cuando sepa EXACTAMENTE lo que está pasando. Cualquier entrada del usuario que ingrese DEBE ser verificada y validada y todo. Si no sabe cómo estar 100% seguro, no lo haga.
Básicamente, un usuario puede escribir cualquier código para el idioma en cuestión, y se ejecutará. Puedes imaginar por ti mismo cuánto daño puede hacer.
fuente
"¿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 usarla
eval
.fuente
En mi opinión, esta pregunta no es específica de LISP . Aquí hay una respuesta sobre la misma pregunta para PHP, y se aplica a LISP, Ruby y otro lenguaje que tiene una evaluación:
Tomado de aquí .
Creo que la parte difícil es un punto sorprendente. La obsesión con el código golf y el código conciso siempre ha resultado en un código "inteligente" (para el cual las evaluaciones son una gran herramienta). Pero debe escribir su código para facilitar la lectura, IMO, para no demostrar que es un astuto y no para ahorrar papel (de todos modos no lo imprimirá).
Luego, en LISP hay algún problema relacionado con el contexto en el que se ejecuta eval, por lo que el código no confiable podría tener acceso a más cosas; Este problema parece ser común de todos modos.
fuente
Ha habido muchas respuestas excelentes, pero aquí hay otra toma de Matthew Flatt, uno de los implementadores de Racket:
http://blog.racket-lang.org/2011/10/on-eval-in-dynamic-languages-generally.html
Explica muchos de los puntos que ya se han cubierto, pero algunas personas pueden encontrar su opinión interesante.
Resumen: el contexto en el que se utiliza afecta el resultado de la evaluación, pero los programadores a menudo no lo tienen en cuenta, lo que genera resultados inesperados.
fuente
La respuesta canónica es mantenerse alejado. Lo cual me parece extraño, porque es un primitivo, y de los siete primitivos (los otros son contras, auto, cdr, if, eq y quote), obtiene la menor cantidad de uso y amor.
De On Lisp : "Por lo general, llamar explícitamente a eval es como comprar algo en una tienda de regalos del aeropuerto. Habiendo esperado hasta el último momento, debe pagar precios altos por una selección limitada de productos de segunda categoría".
Entonces, ¿cuándo uso eval? Un uso normal es tener un REPL dentro de su REPL mediante evaluación
(loop (print (eval (read))))
. Todos están bien con ese uso.Pero también puede definir funciones en términos de macros que se evaluarán después de la compilación combinando eval con backquote. Anda tu
y matará el contexto por ti.
Swank (para emacs slime) está lleno de estos casos. Se ven así:
No creo que sea un truco sucio. Lo uso todo el tiempo para reintegrar macros en funciones.
fuente
Otro par de puntos en Lisp eval:
fuente
Como la "regla" de GOTO: si no sabes lo que estás haciendo, puedes hacer un desastre.
Además de solo construir algo a partir de datos conocidos y seguros, existe el problema de que algunos lenguajes / implementaciones no pueden optimizar el código lo suficiente. Podría terminar con un código interpretado dentro
eval
.fuente
Eval simplemente no es seguro. Por ejemplo, tiene el siguiente código:
Ahora el usuario llega a su sitio e ingresa la url http://example.com/file.php?user= ); $ is_admin = true; echo (
Entonces el código resultante sería:
fuente
eval
cualquier idioma que lo tenga.Eval no es malvada. Eval no es complicado. Es una función que compila la lista que le pasa. En la mayoría de los otros idiomas, compilar código arbitrario significaría aprender el AST del idioma y cavar en las partes internas del compilador para descubrir la API del compilador. En lisp, solo llama a eval.
¿Cuándo deberías usarlo? Siempre que necesite compilar algo, generalmente un programa que acepta, genera o modifica código arbitrario en tiempo de ejecución .
¿Cuándo no deberías usarlo? Todos los otros casos.
¿Por qué no deberías usarlo cuando no lo necesitas? Porque estaría haciendo algo de una manera innecesariamente complicada que puede causar problemas de legibilidad, rendimiento y depuración.
Sí, pero si soy un principiante, ¿cómo sé si debo usarlo? Siempre trate de implementar lo que necesita con las funciones. Si eso no funciona, agregue macros. Si eso todavía no funciona, entonces eval!
Sigue estas reglas y nunca harás mal con eval :)
fuente
Me gusta mucho la respuesta de Zak y ha llegado a la esencia del asunto: eval se usa cuando estás escribiendo un nuevo idioma, un guión o una modificación de un idioma. Realmente no explica más, así que daré un ejemplo:
En este sencillo programa Lisp, se solicita al usuario que ingrese y luego se evalúa lo que ingrese. Para que esto funcione, todo el conjunto de definiciones de símbolos debe estar presente si el programa se compila, porque no tiene idea de qué funciones puede ingresar el usuario, por lo que debe incluirlas todas. Eso significa que si compila este sencillo programa, el binario resultante será gigantesco.
Por principio, ni siquiera puede considerar esto como una declaración compilable por este motivo. En general, una vez que utiliza eval , está operando en un entorno interpretado y el código ya no se puede compilar. Si no utiliza eval , puede compilar un programa Lisp o Scheme como un programa en C. Por lo tanto, desea asegurarse de que desea y necesita estar en un entorno interpretado antes de comprometerse a usar eval .
fuente