Eine große Gefahr besteht darin, dass sich die Bindungssemantik für undefinierte Variablen - dh Variablen, die nicht mit defvarund friends definiert sind - ändert lexical-binding: Ohne sie wird letalles dynamisch lexical-bindinggebunden , aber mit aktivierten undefinierten Variablen wird es lexikalisch gebunden und sogar vollständig beseitigt, wenn es im aktuellen lexikalischen Bereich nicht verwendet wird .
Alter Code stützt sich manchmal darauf. Um harte Abhängigkeiten für optionale Features zu vermeiden, würde es dynamische Variablen binden, ohne die entsprechende Bibliothek zu benötigen oder die Variable selbst zu deklarieren:
(let ((cook-eggs-enabled t))
(cook-my-meal))
Wenn die Kochfunktion optional ist, möchten wir dem Benutzer keine unnötigen Abhängigkeiten (require 'cook)aufzwingen cook-my-meal. Daher verwenden wir die Funktion nicht und verlassen uns stattdessen auf das automatische Laden der Funktion.
Für den menschlichen Leser cook-eggs-enabledist es offensichtlich, dass es sich nicht um eine lokale Variable handelt, sondern dass hier auf eine globale dynamische Variable aus der cookBibliothek verwiesen wird. Ohne lexical-bindingdiesen Code funktioniert wie beabsichtigt: cook-eggs-enabledWird dynamisch gebunden, ob definiert oder nicht.
Mit lexical-bindingaber bricht es: cook-eggs-enabledjetzt gebunden ist lexikalisch (und dann weg optimiert, weil es nicht verwendet wird ), so dass die globale dynamische Variable cook-eggs-enabledist nicht immer überhaupt und noch berührt nilvon der Zeit cook-my-mealaufgerufen wird , so werden wir überraschenderweise keine Eier in unserer Mahlzeit.
Glücklicherweise sind diese Probleme sehr leicht zu erkennen : Der Byte-Compiler warnt hier natürlich vor einer nicht verwendeten lexikalischen Bindung.
Die Lösung ist einfach: Fügen Sie entweder eine hinzu (require 'cook)(für Funktionen, die ohnehin nicht wirklich optional sind), oder deklarieren Sie die Variable als dynamische Variable in Ihrem eigenen Code , um harte Abhängigkeiten zu vermeiden . Hierfür gibt es ein spezielles defvarFormular:
(defvar cook-eggs-enabled)
Dies wird cook-eggs-enabledals dynamische Variable definiert , hat jedoch keine Auswirkungen auf die Dokumentzeichenfolge, die load-history(und damit auch auf find-variableFreunde) oder andere Elemente, mit Ausnahme der Bindungsart der Variablen.
cook-eggs-enabledseinen ungebundene wennletbeendet? Ich bin mir ziemlich sicher, dass ich schon einmal auf einen solchen Bug gestoßen bin. Die Defvar ereignete sich in derlet, und dieletVariable wurde später wieder in den ursprünglichen (ungültigen) Zustand versetzt.