How to live with Emacs Lisp dynamic scoping?

It isn’t that bad.

The main problems can appear with ‘free variables’ in functions.

(defun foo (a)
  (* a b))

In above function a is a local variable. b is a free variable. In a system with dynamic binding like Emacs Lisp, b will be looked up at runtime. There are now three cases:

  1. b is not defined -> error
  2. b is a local variable bound by some function call in the current dynamic scope -> take that value
  3. b is a global variable -> take that value

The problems can then be:

  • a bound value (global or local) is shadowed by a function call, possibly unwanted
  • an undefined variable is NOT shadowed -> error on access
  • a global variable is NOT shadowed -> picks up the global value, which might be unwanted

In a Lisp with a compiler, compiling the above function might generate a warning that there is a free variable. Typically Common Lisp compilers will do that. An interpreter won’t provide that warning, one just will see the effect at runtime.

Advice:

  • make sure that you don’t use free variables accidentally
  • make sure that global variables have a special name, so that they are easy to spot in source code, usually *foo-var*

Don’t write

(defun foo (a b)
   ...
   (setq c (* a b))  ; where c is a free variable
   ...)

Write:

(defun foo (a b)
   ...
   (let ((c (* a b)))
     ...)
   ...)

Bind all variables you want to use and you want to make sure that they are not bound somewhere else.

That’s basically it.

Since GNU Emacs version 24 lexical binding is supported in its Emacs Lisp. See: Lexical Binding, GNU Emacs Lisp Reference Manual.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)