Il y a plusieurs raisons pour lesquelles on ne devrait pas utiliser EVAL
.
La principale raison pour les débutants est: vous n'en avez pas besoin.
Exemple (en supposant Common Lisp):
ÉVALUER une expression avec différents opérateurs:
(let ((ops '(+ *)))
(dolist (op ops)
(print (eval (list op 1 2 3)))))
C'est mieux écrit comme suit:
(let ((ops '(+ *)))
(dolist (op ops)
(print (funcall op 1 2 3))))
Il y a beaucoup d'exemples où les débutants apprenant Lisp pensent qu'ils ont besoin EVAL
, mais ils n'en ont pas besoin - puisque les expressions sont évaluées et on peut également évaluer la partie fonction. 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 écrivent des macros, où ils devraient écrire des fonctions - ne comprenant pas à quoi servent réellement les macros et ne comprenant pas qu'une fonction fait déjà le travail.
C'est souvent le mauvais outil à utiliser pour le travail EVAL
et cela indique souvent que le débutant ne comprend pas les règles d'évaluation Lisp habituelles.
Si vous pensez que vous en avez besoin EVAL
, vérifiez si quelque chose comme FUNCALL
, REDUCE
ou APPLY
pourrait être utilisé à la place.
FUNCALL
- appeler une fonction avec des arguments: (funcall '+ 1 2 3)
REDUCE
- appeler une fonction sur une liste de valeurs et combiner les résultats: (reduce '+ '(1 2 3))
APPLY
- appeler une fonction avec une liste que les arguments: (apply '+ '(1 2 3))
.
Q: ai-je vraiment besoin d'eval ou est-ce que le compilateur / évaluateur est déjà ce que je veux vraiment?
Les principales raisons à éviter EVAL
pour les utilisateurs légèrement plus avancés:
vous voulez vous assurer que votre code est compilé, car le compilateur peut vérifier le code pour de nombreux problèmes et génère du code plus rapide, parfois BEAUCOUP BEAUCOUP (c'est le facteur 1000 ;-)) code plus rapide
le code construit et qui doit être évalué ne peut pas être compilé le plus tôt possible.
L'évaluation des entrées arbitraires de l'utilisateur pose des problèmes de sécurité
une certaine utilisation de l'évaluation avec EVAL
peut se produire au mauvais moment et créer des problèmes de construction
Pour expliquer le dernier point avec un exemple simplifié:
(defmacro foo (a b)
(list (if (eql a 3) 'sin 'cos) b))
Donc, je peux vouloir écrire une macro qui, basée sur le premier paramètre, utilise soit SIN
ou COS
.
(foo 3 4)
fait (sin 4)
et (foo 1 4)
fait (cos 4)
.
Maintenant, nous pouvons avoir:
(foo (+ 2 1) 4)
Cela ne donne pas le résultat souhaité.
On peut alors vouloir réparer la macro FOO
en évaluant 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 connue au moment de la compilation.
Une raison générale importante à éviter EVAL
: il est souvent utilisé pour des hacks laids.