;; ;; This is an Emacs LISP buffer, saved in lisp-interaction-mode. ;; Emacs used dynamic binding/scoping till about Emacs-24, when it ;; introduced lexical scoping as an option. It then went further and switched ;; to lexical scoping by default. Now lexical scoping is the default, but it ;; can be switched off, on per-buffer basis, to use dynamic scoping. ;; Switching to lexical binding changes bytecode generated for eLisp ;; functions. If you haven't already, read about Emacs bytecode: ;; http://nullprogram.com/blog/2014/01/04/ lexical-binding ; the default t ;; We'll switch to dynamic binding, the way Emacs used to be before Emacs-24: (setq lexical-binding nil) nil (defun test (x) (list x y)) test (symbol-function 'test) #[(x) ((list x y)) nil] ;; note the absence of the constants vector, etc. (disassemble 'test) byte code for test: args: (x) 0 varref x ; <-- look up "x" in the symbol table, by name "x", put on stack 1 varref y ; <-- look up "y" in the symbol table, by name "y", put on stack 2 list2 3 return (test 'a) ;; gives us an error, "y" is unbound, cannot be looked up Debugger entered--Lisp error: (void-variable y) (list x y) test(a) eval((test 'a) nil) elisp--eval-last-sexp(t) #f(compiled-function () #)() eval-last-sexp(t) eval-print-last-sexp(nil) ;; So we'll supply a binding for "y": (let ((y 'b)) (test 'a)) (a b) ; <-- y's binding is picked up (let ((y 'c)) (test 'a)) (a c) ; <-- y's current binding is picked up (setq y 'd) d (test 'a) ; <-- y's global binding is picked up (a d) (setq y 1000) ; <-- changed global binding will be picked up too 1000 (test 'a) (a 1000) ;;; Let's now "reboot the world" with lexical binding! (setq lexical-binding t) t (let ((y 'b)) (defun test (x) (list x y))) test y 1000 (test 'a) ; TEST is a closure, it was created with y bound to 'b (a b) (symbol-function 'test) #[(x) ((list x y)) ((y . b))] ; <<-- note the difference! (disassemble 'test) byte code for test: doc: ... args: (arg1) 0 dup 1 constant b ; <<-- the opcode is "get me the first member of the constants vector 2 list2 3 return (byte-compile 'test) #[257 "\211\300D\207" [b] 3 " ;; look up opcode \300 in the opcodes manual (fn X)"] (let ((y 'c)) ; no local or global bindings matter anymore, TEST carries its closure (test 'a)) ; with "b" and doesn't even remember the name of "y". (a b) (let ((y 1000)) (test 'a)) (a b)