Uma grande armadilha é que a semântica de ligação para variáveis indefinidas - ou seja, variáveis não definidas com defvar
e amigos - muda com lexical-binding
: Sem ela, let
vincula tudo dinamicamente, mas com lexical-binding
variá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-meal
função.
É óbvio para o leitor humano que cook-eggs-enabled
não é uma variável local, mas ainda se refere a alguma variável dinâmica global da cook
biblioteca aqui. Sem lexical-binding
esse código, funciona como pretendido: cook-eggs-enabled
é vinculado dinamicamente, definido ou não.
Com lexical-binding
entanto, ele quebra: cook-eggs-enabled
agora é 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 nil
no 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 defvar
formulário especial para isso:
(defvar cook-eggs-enabled)
Isso define cook-eggs-enabled
como variável dinâmica, mas não afeta a sequência de caracteres, o load-history
(e, portanto, os find-variable
amigos) ou qualquer outra coisa, exceto a natureza vinculativa da variável.
cook-eggs-enabled
fosse liberado aolet
terminar? Tenho certeza de que já encontrei um bug como esse antes. O defvar estava acontecendo dentro dolet
, elet
depois restaurou a variável ao seu estado inicial (nulo).