strange interaction between lexical-binding and defvar in emacs lisp

dynamic-scope, elisp, emacs, lexical-scope, lisp

Solution

What is going on

From the "theoretical" (Scheme/Common Lisp) point of view, as soon as you enable lexical bindings, for all practical purposes `alice-multiplier-1` and `alice-multiplier-2` are identical. Any difference in their behavior is a bug in Emacs Lisp and should be reported as such.

Compiled

If you put your code (i.e., the 2 `defun`s and the `;; -*- lexical-binding: t; -*-` line) into a file, `emacs-list-byte-compile-and-load` it, then you can test my claim by evaluating these 4 forms:

(disassemble 'alice-multiplier-1)
(disassemble 'alice-multiplier-2)
(disassemble (alice-multiplier-1 10))
(disassemble (alice-multiplier-2 10))

you will see that 3 and 4 are identical and 1 and 2 differ by one instruction (which should be reported as a bug to the Emacs maintainers, but does not affect the behavior).

Note that none of the disassemblies mention `foo`, which means that the `defvar` will not affect their behavior.

All is good!

Interpreted

Indeed, the behavior you see is incorrect; the correct result after `defvar` is

(:R1 (10000 20000 30000) :R2 (10000 20000 30000))

please report this to the emacs maintainers.

Different???

Yes, `defvar` does (and should!) affect the behavior of interpreted code and does not (and should not!) affect the behavior of compiled code.

What you should do

There is no way to "protect" your `foo` from being proclaimed `special` by others - except by prefixing "your" symbols with `alice-`.

However, if you byte-compile the file with the `alice-multiplier-1` definition, the compiled file does not even contain `foo` and thus future declarations of `foo` will not affect you.

Problem

The following emacs lisp file is about seeing what happens when Alice uses a lexically bound local variable `foo` in her init file and Bob defines `foo` as a global special variable with `defvar` in his init file and Alice borrows part of Bob's init file code into her own init file not knowing that `foo` is going to turn special. ``` ;; -*- lexical-binding: t; -*- ;; Alice init file ;; Alice defining alice-multiplier (defun alice-multiplier-1 (foo) (lambda (n) (* n foo))) (defun alice-multiplier-2 (num) (let ((foo num)) (lambda (n) (* n foo)))) ;; Alice using alice-multiplier (print (list :R1 (mapcar (alice-multiplier-1 10) (list 1 2 3)) :R2 (mapcar (alice-multiplier-2 10) (list 1 2 3)))) ;; from Bob's code ;; ... (defvar foo 1000) ;; ... ;; Alice using alice-multiplier (print (list :R3 (mapcar (alice-multiplier-1 10) (list 1 2 3)) :R4 (mapcar (alice-multiplier-2 10) (list 1 2 3)))) ``` Output: ``` (:R1 (10 20 30) :R2 (10 20 30)) (:R3 (10 20 30) :R4 (1000 2000 3000)) ``` Results R1 and R2 are just as what I expect. Result R4 is consistent with defvar documentation, although it may surprise Alice unless she reads Bob's code. I find R3 surprising. Why is R3 like that? Speaking of R4, what can Alice do to protect her `foo` from turning special by others? For example, `foo` may be a lexical local variable she uses in her init file or one of her emacs package, and `(defvar foo "something")` may be in some of the packages she happens to use, or `foo` could be one of the new special variable names introduced by a future version of Emacs. Is there something Alice can put in her file that says to Emacs "In this file, foo should be always lexical, even if some code from outside happens to use a special variable of the same name"?

Original source