Search code examples
emacselispemacs24

Lexical eval in emacs24


Can anybody explain me how eval works with emacs24? From eval description:

eval is a built-in function in `C source code'.

(eval FORM &optional LEXICAL)

Evaluate FORM and return its value.
If LEXICAL is t, evaluate using lexical scoping.

Does that mean, that something like this should work?

(setq lexical-binding t)
(let ((myvarr 42)) (eval 'myvarr t)) ; (void-variable myvarr)

Update:

(setq lexical-binding nil)
;; => nil
(let ((myvarr 42)) (eval 'myvarr))
;; => 42 (#o52, #x2a, ?*)
(setq lexical-binding t)
;; => t
(let ((myvarr 42)) (eval 'myvarr))
;; Debugger entered--Lisp error: (void-variable myvarr)
;;   eval(myvarr)
;;   (let ((myvarr 42)) (eval (quote myvarr)))
;;   (progn (let ((myvarr 42)) (eval (quote myvarr))))
;;   eval((progn (let ((myvarr 42)) (eval (quote myvarr)))) t)
;;   eval-last-sexp-1((4))
;;   eval-last-sexp((4))
;;   call-interactively(eval-last-sexp nil nil)
;;   call-last-kbd-macro(nil kmacro-loop-setup-function)
;;   kmacro-call-macro(nil nil)
;;   kmacro-end-or-call-macro(nil)
;;   call-interactively(kmacro-end-or-call-macro nil nil)
(ignore-errors (let ((myvarr 42)) (eval 'myvarr)))
;; => nil
(setq lexical-binding nil)
;; => nil
(eval (let ((myvarr 42)) (eval 'myvarr)) t)
;; => 42
(eval '(let ((myvarr 42)) (eval 'myvarr)) t)
;; Debugger entered--Lisp error: (void-variable myvarr)
;;   eval(myvarr)
;;   (let ((myvarr 42)) (eval (quote myvarr)))
;;   eval((let ((myvarr 42)) (eval (quote myvarr))) t)
;;   eval((eval (quote (let ((myvarr 42)) (eval (quote myvarr)))) t) nil)
;;   eval-last-sexp-1((4))
;;   eval-last-sexp((4))
;;   call-interactively(eval-last-sexp nil nil)

Emacs version: GNU Emacs 24.1.1 (i386-mingw-nt6.1.7600) of 2012-06-10 on MARVIN


Solution

  • Since lexical binding breaks much existing elisp code, it is an opt-in feature.

    lexical scoping can best be understood with a simple example:

    (defun some-func (callback)
     (let ((a 5))
      (funcall callback)))
    
    (let ((a 3))
     (some-func (lambda () a)))
    

    Under most languages, this would return 3 since the a in some-func doesn't seem visible from the bottom form. However, in emacs before 24 or without lexical scope this program returns 5.

    This has led to many unexpected surprises and subtle and often hidden bugs between interacting functions; to fix this emacs 24 introduced lexical scoping, but as mentioned previously, is backwards compatible.

    The mechanism to opt-in to dynamic scoping is either the file variable lexical-binding (which turns it on per source file) or as the option you see to eval

    So if we rewrite the example to use eval:

    (eval '(let ((a 3))
            (some-func (lambda () a))) nil) ; => 5
    
    (eval '(let ((a 3))
            (some-func (lambda () a))) t) ; => 3
    

    In your example, what is making the difference is not whether the code inside eval is dynamically scoped, but whether the code surrounding it is. Variable binding is what is affected by lexical scoping, not variable lookup. I'm not completely certain of eval's semantics here, but what seems to be happening (and what makes the most sense) is eval evaluates the expression in an entirely new lexical context. So the outer lexical scope is hidden from the inside of eval, but the dynamic scope is still visible (so the lookup succeeds when the file is dynamically scoped, but not otherwise).