Je sais que les programmeurs Lisp et Scheme disent généralement que cela eval
devrait être évité à moins que cela ne soit strictement nécessaire. J'ai vu la même recommandation pour plusieurs langages de programmation, mais je n'ai pas encore vu une liste d'arguments clairs contre l'utilisation de eval
. Où puis-je trouver un compte rendu des problèmes potentiels d'utilisation eval
?
Par exemple, je connais les problèmes de la GOTO
programmation procédurale (rend les programmes illisibles et difficiles à maintenir, rend les problèmes de sécurité difficiles à trouver, etc.), mais je n'ai jamais vu les arguments contre eval
.
Fait intéressant, les mêmes arguments contre GOTO
devraient être valables contre les continuations, mais je vois que Schemers, par exemple, ne dira pas que les continuations sont «mauvaises» - vous devez juste être prudent lorsque vous les utilisez. Ils sont beaucoup plus susceptibles de froncer les sourcils sur l'utilisation de code eval
que sur le code utilisant des continuations (pour autant que je sache, je peux me tromper).
Réponses:
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:
C'est mieux écrit comme suit:
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 deEVAL
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 commeFUNCALL
,REDUCE
ouAPPLY
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 constructionPour expliquer le dernier point avec un exemple simplifié:
Donc, je peux vouloir écrire une macro qui, basée sur le premier paramètre, utilise soit
SIN
ouCOS
.(foo 3 4)
fait(sin 4)
et(foo 1 4)
fait(cos 4)
.Maintenant, nous pouvons avoir:
Cela ne donne pas le résultat souhaité.
On peut alors vouloir réparer la macro
FOO
en évaluant la variable:Mais alors cela ne fonctionne toujours pas:
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.la source
eval
simplement parce qu'ils ne savent pas qu'il existe une langue ou une fonctionnalité de bibliothèque spécifique pour faire ce qu'ils veulent faire. Exemple similaire de JS: je veux obtenir une propriété d'un objet en utilisant un nom dynamique, alors j'écris:eval("obj.+" + propName)
quand j'aurais pu écrireobj[propName]
."obj.+"
? La dernière fois que j'ai vérifié,+
n'est pas valide lors de l'utilisation de références de points dans JS.eval
(dans n'importe quelle langue) n'est pas mal de la même manière qu'une tronçonneuse n'est pas mal. C'est un outil. Il se trouve que c'est un outil puissant qui, lorsqu'il est mal utilisé, peut couper des membres et éviscérer (métaphoriquement parlant), mais il en va de même pour de nombreux outils dans la boîte à outils d'un programmeur, notamment:goto
et amisSi vous devez utiliser l'un de ces outils puissants et potentiellement dangereux, demandez-vous trois fois "pourquoi?" dans une chaîne. Par exemple:
Si vous arrivez au bout de cette chaîne et que l'outil semble toujours être la bonne chose à faire, faites-le. Documentez l'enfer hors de lui. Testez l'enfer hors de lui. Vérifiez l'exactitude et la sécurité encore et encore et encore. Mais fais-le.
la source
Eval est très bien, tant que vous savez exactement ce qui se passe. Toute entrée d'utilisateur qui y est entrée DOIT être vérifiée et validée et tout. Si vous ne savez pas comment être sûr à 100%, 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 les dégâts qu'il peut faire.
la source
"Quand devrais-je utiliser
eval
?" pourrait être une meilleure question.La réponse courte est "lorsque votre programme est destiné à écrire un autre programme au moment de l'exécution, puis à l'exécuter". La programmation génétique est un exemple de situation dans laquelle son utilisation est probablement logique
eval
.la source
OMI, cette question n'est pas spécifique au LISP . Voici une réponse à la même question pour PHP, et elle s'applique à LISP, Ruby et à d'autres langages qui ont une évaluation:
Pris d' ici .
Je pense que la pièce délicate est un point incroyable. L'obsession du code golf et du code concis a toujours abouti à un code "intelligent" (pour lequel les evals sont un excellent outil). Mais vous devriez écrire votre code pour plus de lisibilité, IMO, pour ne pas démontrer que vous êtes intelligent et pour ne pas économiser du papier (vous ne l'imprimerez pas de toute façon).
Ensuite, dans LISP, il y a un problème lié au contexte dans lequel eval est exécuté, donc du code non approuvé pourrait avoir accès à plus de choses; ce problème semble de toute façon courant.
la source
Il y a eu beaucoup de bonnes réponses, mais voici une autre prise de Matthew Flatt, l'un des implémenteurs de Racket:
http://blog.racket-lang.org/2011/10/on-eval-in-dynamic-languages-generally.html
Il fait valoir bon nombre des points qui ont déjà été abordés, mais certaines personnes peuvent néanmoins trouver son point de vue intéressant.
Résumé: Le contexte dans lequel il est utilisé affecte le résultat de eval mais n'est souvent pas pris en compte par les programmeurs, ce qui entraîne des résultats inattendus.
la source
La réponse canonique est de rester à l'écart. Ce que je trouve bizarre, car c'est un primitif, et des sept primitifs (les autres étant contre, voiture, cdr, if, eq et quote), il obtient de loin le moins d'utilisation et d'amour.
De On Lisp : "Habituellement, appeler eval de manière explicite, c'est comme acheter quelque chose dans une boutique de cadeaux d'aéroport. Après avoir attendu le dernier moment, vous devez payer des prix élevés pour une sélection limitée de produits de second ordre."
Alors, quand utiliser eval? Une utilisation normale est d'avoir une REPL dans votre REPL en évaluant
(loop (print (eval (read))))
. Tout le monde est d'accord avec cette utilisation.Mais vous pouvez également définir des fonctions en termes de macros qui seront évaluées après compilation en combinant eval avec backquote. Tu vas
et cela tuera le contexte pour vous.
Swank (pour emacs slime) est plein de ces cas. Ils ressemblent à ceci:
Je ne pense pas que ce soit un sale hack. Je l'utilise moi-même tout le temps pour réintégrer des macros dans des fonctions.
la source
Un autre couple de points sur l'évaluation Lisp:
la source
Comme la "règle" GOTO: si vous ne savez pas ce que vous faites, vous pouvez faire un gâchis.
En plus de ne construire que quelque chose à partir de données connues et sûres, il y a le problème que certains langages / implémentations ne peuvent pas optimiser suffisamment le code. Vous pourriez vous retrouver avec du code interprété à l'intérieur
eval
.la source
Eval n'est tout simplement pas sûr. Par exemple, vous avez le code suivant:
Maintenant, l'utilisateur accède à votre site et entre l'URL http://example.com/file.php?user= ); $ is_admin = true; echo (
Ensuite, le code résultant serait:
la source
eval
n'importe quel langage qui en avait.Eval n'est pas mauvais. L'évaluation n'est pas compliquée. C'est une fonction qui compile la liste que vous lui passez. Dans la plupart des autres langages, compiler du code arbitraire signifierait apprendre l'AST du langage et fouiller dans les composants internes du compilateur pour comprendre l'API du compilateur. Dans lisp, vous appelez simplement eval.
Quand devriez-vous l'utiliser? Chaque fois que vous avez besoin de compiler quelque chose, généralement un programme qui accepte, génère ou modifie du code arbitraire au moment de l'exécution .
Quand ne devriez-vous pas l'utiliser? Tous les autres cas.
Pourquoi ne devriez-vous pas l'utiliser lorsque vous n'en avez pas besoin? Parce que vous feriez quelque chose d'une manière inutilement compliquée qui pourrait causer des problèmes de lisibilité, de performances et de débogage.
Ouais, mais si je suis un débutant, comment savoir si je dois l'utiliser? Essayez toujours d'implémenter ce dont vous avez besoin avec des fonctions. Si cela ne fonctionne pas, ajoutez des macros. Si cela ne fonctionne toujours pas, évaluez!
Suivez ces règles et vous ne ferez jamais de mal avec eval :)
la source
J'aime beaucoup la réponse de Zak et il a compris l'essentiel du problème: eval est utilisé lorsque vous écrivez une nouvelle langue, un script ou une modification d'une langue. Il n'explique pas vraiment plus loin donc je vais donner un exemple:
Dans ce programme Lisp simple, l'utilisateur est invité à entrer, puis tout ce qu'il entre est évalué. Pour que cela fonctionne l' ensemble ensemble de définitions de symboles doit être présent si le programme est compilé, parce que vous ne savez pas quelles fonctions l'utilisateur peut entrer, vous devez les inclure. Cela signifie que si vous compilez ce programme simple, le binaire résultant sera gigantesque.
En principe, vous ne pouvez même pas considérer cela comme une déclaration compilable pour cette raison. En général, une fois que vous utilisez eval , vous travaillez dans un environnement interprété et le code ne peut plus être compilé. Si vous n'utilisez pas eval, vous pouvez compiler un programme Lisp ou Scheme comme un programme C. Par conséquent, vous voulez vous assurer que vous voulez et devez être dans un environnement interprété avant de vous engager à utiliser eval .
la source