Saturday, April 09, 2011

A brief demonstration of emacs new lexical bindings

It wasn't a joke.  On April 1st, Stefan Monnier merged the lexical binding branch into the emacs trunk.  Unless it needs to be rolled back, emacs 24 should have lexical binding, which is a huge improvement for elisp.  If you want to try it out, get the latest emacs from source, and compile it yourself.

To enable it, you need to set lexical-binding to t.  This is buffer local, so you need to set it for every buffer that you want to have lexical binding in.

Here's a demonstration in an ielm session (M-x ielm).
ELISP> (setq lexical-binding t)
t
ELISP> (defun make-adder (base) (lambda (num) (+ num base)))
make-adder
ELISP> (setq x 1)
1
ELISP> (setq 1-adder (make-adder x))
(closure
((base . 1)
t)
(num)
(+ num base))
ELISP> (funcall 1-adder 10)
11
ELISP> (funcall 1-adder 100)
101
ELISP> (setq x 100)
100
ELISP> (funcall 1-adder 100)
101
Without lexical binding, the variable x would be a dynamic variable, and so when we set it to 100 later in the session, the 1-adder would change to a 100-adder inadvertently.  In fact, if we try, we can't even get to that point.  Here's the same session without lexical binding:
ELISP> lexical-binding
nil
ELISP> (defun make-adder (base) (lambda (num) (+ num base)))
make-adder
ELISP> (setq x 1)
1
ELISP> (setq 1-adder (make-adder x))
(lambda
(num)
(+ num base))
ELISP> (funcall 1-adder 10)
*** Eval error *** Symbol's value as variable is void: base
What's going on here?  Notice that when we make the 1-adder without lexical binding, we don't get a closure.   Instead, we just get a function that references num and base.  num is passed into the function, but base is a dynamic variable, so it is interpreted in the emacs global context, as opposed to a context inside a closure.  The variable base is not bound to a value in the global context, and when we execute the lambda, which refers to base, emacs looks for the base variable, cannot find it, and throws an error.

This doesn't happen with lexical binding.  In that case, we can actually see the closure itself being returned when there is lexical binding:
(closure
((base . 1)
t)
(num)
(+ num base))
The closure here shows a structure in which we can interpret to mean that base is being bound to 1.  You can also see num is the argument (since it is not in the same s-expression as the binding of base), and then it proceeds with the simple addition function.

I haven't yet made use of closures in my emacs code.  I don't really need it in my initialization files, and if I writes modules that assume it then almost no one can yet use it.  So I'll give it time, but it's a huge step in making elisp a better lisp.  Read more about lexical bindings Paul Graham's wonderful free book On Lisp.

Lexical bindings are not only a good feature in themselves, they are also is an important step on the way to multithreading.  Having nothing but global variables makes threading quite challenging, and lexical bindings in the standard elisp packages can help make multithreading easier.