버퍼에 대한 어휘 바인딩을 가능하게하는 잠재적 인 함정은 무엇입니까?


12

이것은 이 질문 에서 어휘 바인딩어휘 -let 에 대한 토론에서 영감을 얻었습니다 . 어휘 바인딩 은 사람들이 JavaScript와 같은 다른 언어로 익숙해 지면서 유용한 클로저를 가질 수있는 능력을 제공하므로 왜 항상 활성화하지 않겠습니까?

이전 Emacsen과의 하위 호환성을 가정한다고해서 레거시 코드 버퍼에서 활성화 할 경우 어떤 함정을 고려해야합니까?

답변:


13

주요 함정에 대한 바인딩을 의미한다는 것입니다 정의되지 않은 변수 - 즉 변수가 정의되지 defvar친구들-변화 lexical-binding없이, : let바인딩의 모든 동적으로하지만, 함께 lexical-binding활성화 정의되지 않은 변수 바인딩 어휘 , 심지어 현재 어휘 범위 완전히 사용하지 않는 경우 생략 .

오래된 코드는 때때로 이것에 의존합니다. 선택적 기능에 대한 엄격한 종속성을 피하기 위해 해당 라이브러리가 필요 하지 않거나 변수 자체를 선언 하지 않고 동적 변수 바인딩 합니다.

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

쿠킹 기능이 옵션 인 경우, 사용자에게 불필요한 의존성을 강요하고 싶지 않으므로 함수를 사용하지 않고 (require 'cook)대신 자동 로딩에 의존 cook-my-meal합니다.

인간 독자 cook-eggs-enabled에게는 지역 변수가 아니지만 여전히 cook라이브러리의 전역 동적 변수를 참조하는 것이 분명 합니다. lexical-binding이 코드가 없으면 의도 한대로 작동 cook-eggs-enabled합니다. 정의 여부에 관계없이 동적으로 바인딩됩니다.

lexical-binding: 그러나, 휴식 cook-eggs-enabled이제 바인딩 어휘 (사용하지 않을 있기 때문에 멀리하고 최적화) 글로벌 동적 변수가 있도록 cook-eggs-enabled되어 있지 지금까지 여전히 전혀 감동과 nil시간에 의해 cook-my-meal이라고 우리는 놀라 울 정도로 어떤 달걀이되지 않도록, 우리의 식사에서.

운 좋게도 이러한 문제는 쉽게 발견 할 수 있습니다 . 바이트 컴파일러는 자연스럽게 사용되지 않는 어휘 바인딩에 대해 경고 합니다.

해결 방법은 간단합니다. (require 'cook)(어쨌든 선택 사항이 아닌 기능의 경우)를 추가 하거나 어려운 종속성을 피하기 위해 변수 를 자신의 코드에서 동적 변수로 선언하십시오 . 이에 대한 특별한 defvar형식이 있습니다.

(defvar cook-eggs-enabled)

이것은 cook-eggs-enabled동적 변수로 정의 되지만 변수 의 바인딩 특성을 제외하고 docstring, load-history(및 따라서 find-variable친구) 또는 다른 것에 영향을 미치지 않습니다 .


동적 경우, 코드의 원인은하지 않을 것이라고 cook-eggs-enabled할 수 언 바운드let완료? 나는 전에 이와 같은 버그가 발생했다고 확신합니다. defvar은 내부에서 발생 let했으며 let나중에 변수를 초기 (void) 상태로 복원했습니다.
Malabarba

1
@ 말라 바바 아니, 그건 다른 상황이다. 이유는 변수 정의 의 마지막 단락을 참조하십시오 .
lunaryorn
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.