Quali sono le potenziali insidie ​​di abilitare il legame lessicale per un buffer?


12

Ciò è stato ispirato dalla discussione sul legame lessicale contro il lessico lessico in questa domanda . Dato che il legame lessicale ti dà la possibilità di avere chiusure utili a cui le persone potrebbero essere abituate in altre lingue come JavaScript, perché non lo abiliti sempre?

Supponendo che la retrocompatibilità con Emacsen precedente non costituisca una preoccupazione per quali insidie ​​dovresti cercare se abilitarlo nei buffer di codice legacy?

Risposte:


13

Un importante trabocchetto è che la semantica vincolanti per non definite le variabili variabili-vale a dire non definiti con defvargli amici-cambio con lexical-binding: Senza di esso, letil vincolo in modo dinamico, ma con lexical-bindingle variabili non definite abilitati sono tenuti lessicalmente , e anche completamente elise se non utilizzato nella corrente scope lessicale .

Il vecchio codice a volte si basa su questo. Per evitare forti dipendenze per le funzionalità opzionali, assocerebbe le variabili dinamiche senza richiedere la libreria corrispondente o dichiarare la variabile stessa:

(let ((cook-eggs-enabled t))
  (cook-my-meal))

Se la funzione di cottura è opzionale, non vogliamo imporre dipendenze non necessarie all'utente, quindi non utilizziamo (require 'cook)e facciamo affidamento sul caricamento automatico della cook-my-mealfunzione.

È ovvio per il lettore umano che cook-eggs-enablednon è una variabile locale, ma fa ancora riferimento a qualche variabile dinamica globale della cooklibreria qui. Senza lexical-bindingquesto codice funziona come previsto: cook-eggs-enabledè associato in modo dinamico, definito o no.

Con lexical-bindingperò, si rompe: cook-eggs-enabledè ora legata lessicale (e poi ottimizzata via, perché non è utilizzato), quindi la variabile dinamica globale cook-eggs-enabledè non mai toccato a tutti e ancora nilper il momento cook-my-mealsi chiama, in modo che sorprendentemente non avrà alcun uova nel nostro pasto.

Fortunatamente, questi problemi sono molto facili da individuare : il compilatore di byte avverte naturalmente di un legame lessicale inutilizzato qui.

La correzione è semplice: aggiungi un (require 'cook)(per le funzionalità che non sono comunque facoltative) o, per evitare dipendenze difficili, dichiara la variabile come variabile dinamica nel tuo codice . Esiste un defvarmodulo speciale per questo:

(defvar cook-eggs-enabled)

Questo definisce cook-eggs-enableduna variabile dinamica, ma non influenza il docstring, il load-history(e quindi gli find-variableamici) o qualsiasi altra cosa, tranne la natura vincolante della variabile.


Nel caso dinamico, non sarebbe che frammento di codice causa cook-eggs-enableddi essere non legato quando letfiniture? Sono abbastanza sicuro di essermi imbattuto in un bug come questo prima. La defvar stava accadendo all'interno di let, e letsuccessivamente ripristinò la variabile al suo stato iniziale (vuoto).
Malabarba,

1
@Malababa No, questa è una situazione diversa. Vedere l'ultimo paragrafo di Definizione delle variabili per il motivo.
lunaryorn,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.