Uma grande armadilha é que a semântica de ligação para variáveis indefinidas - ou seja, variáveis não definidas com defvare amigos - muda com lexical-binding: Sem ela, letvincula tudo dinamicamente, mas com lexical-bindingvariáveis indefinidas ativadas é vinculada lexicamente e até elidida completamente se não for usada no escopo lexical atual .
Às vezes, o código antigo depende disso. Para evitar dependências rígidas para recursos opcionais, ele vincularia variáveis dinâmicas sem exigir a biblioteca correspondente ou declarar a própria variável:
(let ((cook-eggs-enabled t))
(cook-my-meal))
Se o recurso de cozimento for opcional, não queremos impor dependências desnecessárias ao usuário; portanto, não usamos (require 'cook)e, em vez disso, dependemos do carregamento automático da cook-my-mealfunção.
É óbvio para o leitor humano que cook-eggs-enablednão é uma variável local, mas ainda se refere a alguma variável dinâmica global da cookbiblioteca aqui. Sem lexical-bindingesse código, funciona como pretendido: cook-eggs-enabledé vinculado dinamicamente, definido ou não.
Com lexical-bindingentanto, ele quebra: cook-eggs-enabledagora é obrigado lexically (e, em seguida, otimizado para longe, porque não é usado), então a variável dinâmica mundial cook-eggs-enabledé não já tocou em tudo e ainda nilno momento em que cook-my-mealé chamado, de modo que, surpreendentemente, não terá quaisquer ovos na nossa refeição.
Felizmente, esses problemas são muito fáceis de identificar : o compilador de bytes naturalmente alerta sobre uma ligação lexical não utilizada aqui.
A correção é simples: adicione um (require 'cook)(para recursos que não são realmente opcionais de qualquer maneira) ou, para evitar dependências graves, declare a variável como variável dinâmica em seu próprio código . Existe um defvarformulário especial para isso:
(defvar cook-eggs-enabled)
Isso define cook-eggs-enabledcomo variável dinâmica, mas não afeta a sequência de caracteres, o load-history(e, portanto, os find-variableamigos) ou qualquer outra coisa, exceto a natureza vinculativa da variável.
cook-eggs-enabledfosse liberado aoletterminar? Tenho certeza de que já encontrei um bug como esse antes. O defvar estava acontecendo dentro dolet, eletdepois restaurou a variável ao seu estado inicial (nulo).