Un écueil majeur est que la sémantique de liaison pour les variables non définies - c'est-à-dire les variables non définies avec defvaret amis - change avec lexical-binding: Sans elle, letlie tout dynamiquement, mais avec les lexical-bindingvariables non définies activées sont liées lexicalement , et même élides complètement si inutilisées dans la portée lexicale actuelle .
L'ancien code repose parfois sur cela. Pour éviter les dépendances matérielles pour les fonctionnalités facultatives, il lierait les variables dynamiques sans nécessiter la bibliothèque correspondante ou déclarer la variable elle-même:
(let ((cook-eggs-enabled t))
(cook-my-meal))
Si la fonction de cuisson est facultative, nous ne voulons pas forcer des dépendances inutiles sur l'utilisateur, nous n'utilisons donc pas (require 'cook)et nous nous appuyons plutôt sur le chargement automatique de la cook-my-mealfonction.
Il est évident pour le lecteur humain qu'il cook-eggs-enabledne s'agit pas d'une variable locale, mais se réfère toujours à une variable dynamique globale de la cookbibliothèque ici. Sans lexical-bindingce code fonctionne comme prévu: cook-eggs-enabledest lié dynamiquement, qu'il soit défini ou non.
Avec lexical-bindingcependant, il se casse: cook-eggs-enabledest maintenant lié lexicalement (puis optimisé loin, parce qu'il est pas utilisé), de sorte que la variable globale dynamique cook-eggs-enabledest pas toujours touché du tout et encore nilpar le temps cook-my-mealest appelé, donc nous étonnamment pas des œufs dans notre repas.
Heureusement, ces problèmes sont très faciles à repérer : le compilateur d'octets vous avertit naturellement d'une liaison lexicale inutilisée ici.
La solution est simple: ajoutez un (require 'cook)(pour les fonctionnalités qui ne sont pas vraiment facultatives de toute façon) ou, pour éviter les dépendances matérielles, déclarez la variable comme variable dynamique dans votre propre code . Il existe un defvarformulaire spécial pour cela:
(defvar cook-eggs-enabled)
Cela définit cook-eggs-enabledcomme variable dynamique, mais n'affecte pas la docstring, le load-history(et donc find-variableet amis) ou quoi que ce soit d'autre, sauf la nature contraignante de la variable.
cook-eggs-enabledpas une dissociation à laletfin? Je suis presque sûr d'avoir rencontré un bug comme celui-ci auparavant. Le defvar se produisait à l'intérieur dulet, et leletdernier a restauré la variable à son état initial (vide).