144 votes

Pourquoi exactement est-ce que le mal est eval?

Je sais que Lisp et Scheme programmeurs l'habitude de dire que eval doit être évitée sauf si cela est strictement nécessaire. J'ai vu la même recommandation pour plusieurs langages de programmation, mais je n'ai pas encore vu une liste claire des arguments contre l'utilisation de eval. Où puis-je trouver un compte des problèmes potentiels de l'utilisation d'eval?

Par exemple, je connais les problèmes de GOTO en programmation procédurale (rend les programmes illisible et difficile à maintenir, du fait des problèmes de sécurité difficile à trouver, etc), mais je n'ai jamais vu les arguments contre eval.

Fait intéressant, les mêmes arguments contre GOTO doit être valide contre les poursuites, mais je vois que les Intrigants, par exemple, ne veut pas dire que les continuations sont "mal" -- vous devez juste être prudent lors de leur utilisation. Ils sont beaucoup plus susceptibles de froncer les sourcils sur le code à l'aide eval que sur le code à l'aide de suites (aussi loin que je peux voir, je peux me tromper).

Edit: WOW, c'était rapide! Trois réponses en moins de cinq minutes! Ainsi, les réponses sont:

  • Pas la validation des données des utilisateurs et de l'envoi d'eval est le mal
  • L'utilisation d'eval I peut se retrouver avec le code interprété au lieu de compilé
  • Eval pourrait rendre le code illisible (même si je pense que l'on peut écrire illisible code sans "puissant", donc ce n'est pas vraiment un problème)
  • Les débutants peuvent être confus mélange au moment de la compilation et de l'évaluation en temps quand le mélange eval et les macros (mais je pense que ce n'est pas un problème une fois que vous obtenez une solide compréhension de la façon dont votre langue œuvres, Lisp ou autres)

Jusqu'à présent, il semble que si je générer du code (et non pas directement utiliser quoi que ce soit à partir de la saisie de l'utilisateur directement), et si je sais ce que l'environnement eval sera exécuté; et si je ne suis pas attendre super-rapide de code, puis eval est OK.

154voto

Rainer Joswig Points 62532

Il y a plusieurs raisons pour lesquelles on ne devrait pas utiliser la fonction EVAL.

La principale raison pour les débutants: vous n'en avez pas besoin.

Exemple (en supposant Common Lisp):

EVAL une expression avec les différents opérateurs:

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

C'est mieux écrit que:

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

Il y a des tas d'exemples où les débutants d'apprendre Lisp pensent qu'ils ont besoin EVAL, mais ils n'en a pas besoin car les expressions sont évaluées, et l'on peut également évaluer la fonction de la partie. La plupart du temps l'utilisation de EVAL montre un manque de compréhension de l'évaluateur.

C'est le même problème avec les macros. Souvent les débutants écrire des macros, où ils devraient écrire des fonctions - ne pas comprendre que les macros sont vraiment pour, et ne pas comprendre qu'une fonction déjà fait le travail.

C'est souvent le mauvais outil pour le travail à utiliser EVAL et il indique souvent que le débutant ne comprend pas l'habitude Lisp règles d'évaluation.

Si vous pensez que vous avez besoin d' EVAL, puis de vérifier si quelque chose comme FUNCALL, REDUCE ou APPLY pourrait être utilisé à la place.

Q: ai-je vraiment besoin d'eval ou ne le compilateur/évaluateur déjà ce que je veux vraiment?

Les principales raisons pour éviter d'EVAL pour un peu plus les utilisateurs avancés:

  • vous voulez vous assurer que votre code est compilé, car le compilateur ne peut vérifier le code pour de nombreux problèmes et génère plus rapide de code, parfois beaucoup beaucoup BEAUCOUP (facteur 1000 ;-) )plus rapide code

  • le code est construit et doit être évaluée ne peut pas être compilé le plus tôt possible.

  • eval de l'arbitraire à l'entrée de l'utilisateur ouvre les problèmes de sécurité

  • certains l'utilisation de l'évaluation avec EVAL peut arriver au mauvais moment et de créer des problèmes de compilation

Pour expliquer ce dernier point avec un exemple simplifié:

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

Donc, je peux avoir envie d'écrire une macro qui basé sur le premier paramètre utilise SIN ou COS.

(foo 3 4) (sin (4) et (foo 1 4) (cos 4).

Maintenant, nous pouvons avoir:

(foo (+ 2 1) 4)

Cela ne donne pas le résultat escompté.

On peut alors voulez réparer la macro FOO, par l'ÉVALUATION de la variable:

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

(foo (+ 2 1) 4)

Mais alors, cela ne fonctionne toujours pas:

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

La valeur de la variable n'est tout simplement pas connu au moment de la compilation.

Un général en raison importante pour éviter EVAL: il est souvent utilisé pour les vilaines hacks.

42voto

eval (dans toutes les langues) n'est pas mal de la même manière qu'une tronçonneuse n'est pas mal. C'est un outil. Il arrive à être un outil puissant qui, lorsque mal utilisés, peuvent se séparer des membres et de l'eviscération (métaphoriquement parlant), mais la même chose peut être dit pour de nombreux outils dans une boîte à outils du programmeur, y compris:

  • goto et les amis
  • serrure à base de filetage
  • les continuations
  • les macros (hygiénique ou autres)
  • les pointeurs
  • redémarrage d'exceptions
  • self-modifying code
  • ...et un casting de milliers de personnes.

Si vous vous trouvez avoir à utiliser un de ces puissants, potentiellement dangereux outils posez-vous trois fois "pourquoi?" dans une chaîne. Par exemple:

"Pourquoi dois-je utiliser eval?" "En raison de foo." "Pourquoi est-foo - elle nécessaire?" "Parce que ..."

Si vous arrivez à la fin de la chaîne et de l'outil dirait que c'est la bonne chose à faire, puis le faire. Document de l'Enfer hors de lui. Test de l'Enfer hors de lui. Double-vérifier l'exactitude et la sécurité de plus de et plus et plus de nouveau. Mais le faire.

27voto

Tor Valamo Points 14209

Eval c'est bien, pourvu que vous sachiez EXACTEMENT ce qui s'y passe. Toute entrée d'utilisateur y entrant DOIT être vérifiée et validée et tout. Si vous ne savez pas comment être sûr à 100%, alors ne le faites pas.

Fondamentalement, un utilisateur peut taper n'importe quel code pour la langue en question, et il s'exécutera. Vous pouvez imaginer pour vous combien de dégâts il peut faire.

22voto

Zak Points 887

"Quand devrais-je utiliser eval ?" pourrait être une meilleure question.

La réponse courte est "lorsque votre programme est destiné à écrire un autre programme à l'exécution, puis l'exécuter". La programmation génétique est un exemple de situation où il est probablement logique d'utiliser eval .

15voto

Yar Points 25421

OMI, cette question n'est pas spécifique à LISP. Voici une réponse à la même question pour le PHP, et il s'applique à LISP, Ruby, et d'autres de l'autre langue qui a un eval:

Les principaux problèmes avec la fonction eval() sont:

  • Potentiel dangereux d'entrée. En passant un paramètre non fiables est un moyen de un échec. Il n'est souvent pas une mince tâche assurez-vous que l'un des paramètres (ou une partie de de celui-ci) est entièrement fiable.
  • Trickyness. À l'aide de la fonction eval() rend le code intelligent, donc plus difficile à suivre. Pour citer Brian Kernighan "Le débogage est deux fois plus dur que de l'écriture du code en premier lieu. Donc, si vous écrivez le code habilement que possible, vous êtes, par définition, pas assez intelligent pour le debug c'"

Le principal problème avec l'utilisation réelle de eval() est une seule:

  • inexpérimenté développeurs qui l'utilisent sans considération.

Prises à partir d' ici.

Je pense que le trickyness pièce est un point étonnant. L'obsession du code de golf et concis code a toujours abouti à un "sage" du code (qui est évaluée comme sont un excellent outil). Mais vous devez écrire votre code pour plus de lisibilité, de l'OMI, de ne pas montrer que vous êtes un smarty et ne pas afin d'économiser du papier (vous n'aurez pas l'impression de toute façon).

Puis en LISP il y a quelques soucis liés au contexte dans lequel eval est exécuté, si un code non fiable pourrait avoir accès à plus de choses; ce problème semble être commun, de toute façon.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X