Lexical and dynamic binding refer to how variables are looked up by their names. Lexical binding is sometimes called static binding. The naming contrast between “static binding” and “dynamic binding” is more obvious, however the difference is somewhat more subtle than simply whether a binding changes over time.
A binding is a correspondence between a name and its value.
In Lisp you can create a binding using ‘let’
:
(let ((a 1)) (print a))
==> 1
This creates a fresh location, puts the value 1 there, and binds the name “a” to it.
Each use of ‘let’
creates a fresh location, even if you use the same name:
(let ((a 1)) (let ((a 2)) (let ((a 3)) (print a)) (print a)) (print a)) ==> 3 2 1
A binding made by ‘let’
lasts until the end of the ‘let’
form.
Function calls create bindings for their formal arguments when they are called:
(defun foo (a) (let ((a 2)) (print a)) (print a)) (foo 1) ==> 2 1
A binding made by a function call lasts until the call returns.
A ‘let’
expression is indeed just “syntactic sugar”, a convenience, for the corresponding ‘lambda’
form:
(let ((a 1)
(b 3))
(+ a b))
is equivalent to
((lambda (a b) (+ a b)) 1 3)
Note that there are plenty of other ways to make bindings: ‘defconst’
, ‘defun’
, ‘defvar’
, ‘flet’
, ‘labels’
, ‘prog’
, etc.
Two regimes for handling variable binding emerged:
For the simple examples given above both lexical and dynamic binding return the same results. But consider this piece of code:
(let ((a 1)) ; binding (1) (let ((f (lambda () (print a)))) (let ((a 2)) ; binding (2) (funcall f)))) ==> ?
A name that is lexically bound is looked up only in bindings in the lexical environment of the name – that is, in bindings that enclose the name in the source code. So if “a” is lexically bound, the code above prints “1”, because only binding (1) is in the lexical environment. When there are multiple bindings in the lexical environment, the innermost one is used.
A name that is dynamically bound is looked up only in bindings in the dynamic environment of the name – that is, in all bindings which have been created since the program began and which have not yet been destroyed. When there are multiple bindings in the dynamic environment, the most recently created one is used. So if “a” is dynamically bound, the code above prints “2” because both binding (1) and binding (2) have been created by the time “a” is evaluated, but binding (2) was created more recently.
(In a multi-threaded Lisp we would have to be a bit more careful about dynamic binding to make sure that one thread doesn’t see bindings created on another thread. But EmacsLisp is single-threaded so that’s not a worry.)
This is a lambda function which adds 3 to a number: (lambda (arg) (+ 3 arg))
. You may apply it so: ((lambda (arg) (+ 3 arg)) 5)
and it gives 8.
Now you want to store the 3 somewhere else (let’s say in variable to_add
) but still get a function which adds 3 (not other possible values of to_add, but the current one). You could try: (let ((to_add 3)) (lambda (arg) (+ to_add arg)) )
. But it doesn’t work because you get: (lambda (arg) (+ to_add arg))
instead of (lambda (arg) (+ 3 arg))
. The first one will not work if the value of the variable to_add
had changed by the time the lambda is applied. The cause of this result is that the binding is dynamic, not lexical. Notice the difference.
Now for how to do what you wanted. This wouldn’t work either: (let ((to_add 3)) `(lambda (arg) (+ ,to_add arg)) )
because it is not a closure, it is a substitution (see: BackquoteSyntax). A solution would be: (lexical-let ((to_add 3)) (lambda (arg) (+ to_add arg)))
, which can be applied with funcall: (funcall (lexical-let ((to_add 3)) (lambda (arg) (+ to_add arg))) 5)
is 8. More on the theory is below, and other solutions in FakeClosures.
Dynamic bindings are great for modifying the behaviour of subsystems. Suppose you are using a function ‘foo’
that generates output using ‘print’
. But sometimes you would like to capture the output in a buffer of your choosing. With dynamic binding, it’s easy:
(let ((b (get-buffer-create " *string-output*"))) (let ((standard-output b)) (print "foo")) (set-buffer b) ;; do stuff with the output of foo (insert "bar") (buffer-string))
(And if you used this kind of thing a lot, you’d encapsulate it in a macro – but luckily it’s already been done as ‘with-output-to-temp-buffer’
.)
This works because ‘foo’
uses the dynamic binding of the name ‘standard-output’
, so you can substitute your own binding for that name to modify the behaviour of ‘foo’
– and of all the functions that ‘foo’
calls.
In a language without dynamic binding, you’d probably add an optional argument to ‘foo’
to specify a buffer and then ‘foo’
would pass that to any calls to ‘print’
. But if ‘foo’
calls other functions which themselves call ‘print’
you’ll have to alter those functions as well. And if ‘print’
had another option, say ‘print-level’
, you’d have to add that as an optional argument as well… Alternatively, you could remember the old value of ‘standard-output’
, substitute your new value, call ‘foo’
and then restore the old value. And remember to handle non-local exits using ‘throw’
. When you’re through with this, you’ll see that you’ve implemented dynamic binding!
RichardStallman explains the advantages of dynamic binding in the context of EmacsLisp: http://www.gnu.org/software/emacs/emacs-paper.html#SEC17. See also the article Dynamic vs. Static Typing — A Pattern-Based Analysis by Pascal Costanza, http://www.p-cos.net/documents/dynatype.pdf.
From: MilesBader Subject: Re: Emacs 22 Newsgroups: comp.emacs Date: Sun, 19 Aug 2001 01:47:53 GMT Because it's (1) much easier for the user [that is, programmer], because it eliminates the problem of which variables lambda-expressions use (when they attempt to use variables from their surrounding context), and (2) much easier for the compiler to optimize, because it doesn't need to worry about variables escaping their lexical context, and so doesn't need to allow for the possibility (this is a big problem with the current compiler).
Most languages only have lexical bindings for names.
‘defvar’
ed to make them “special”, like in CommonLisp.‘defvar’
ing or ‘declare’
ing a variable “special”.RichardStallman wrote a paper describing the design of the original Emacs and the lessons to be learned from it. It also contains a great section on dynamic binding.
See node Dynamic Binding in the EmacsLispReference.
To use lexical binding, an Emacs-lisp source file must set a file-local variable ‘lexical-binding’
to ‘t’
in the file header, e.g., by using a first line such as this:
;;; -*- lexical-binding: t -*-
Even in a source file that uses lexical binding, global variables declared with ‘defvar’
are always dynamically scoped.
Much code written for normal EmacsLisp should work unchanged when using lexical binding, because good Lisp programming practice tends to discourage the sort of code that would expose the difference (e.g., ‘let’
-binding an undeclared variable and intending that the value be seen by a called function).
StefanMonnier has said more about how lexical binding in Emacs could behave:
‘let’
both for dynamically-scoped let-bindings and for lexically-scoped let-bindings; where the distinction is based on whether or not a variable has been defvar’d. This is the same system as used in CommonLisp and it works well in practice, but it requires a bit of care, because every defvar has a global effect: it declares that this variable will use dynamic-scoping wherever it gets let-bound. So if a file uses ‘len’
as a lexically-scoped variable and another file does a (defvar len), we get a conflict that results in the first file being evaluated with a different semantic than expected by the author.‘e’
and ‘pi’
.‘float-e’
and ‘float-pi’
, but this introduces a backward incompatibility. I figure we could define-obsolete-variable-alias (which leaves the problem of ‘e’
and ‘pi’
being dynamically scoped, but hopefully only for a few versions until we remove the obsolete name), but this means that every code that does (let ((e <foo> )) …) would now get a stupid warning about using an obsolete variable ‘e’
.‘e’
, ‘float-e’
, ‘pi’
, and ‘float-pi’
and declare ‘e’
and ‘pi’
obsolete, but without a make-obsolete-variable (i.e. only in NEWS and in docstrings). - in Emacs-24 keep float-e and float-pi but get rid of ‘e’
and ‘pi’
.See this page: FakeClosures. Other tips are given below.
If you `(require ‘cl)’ then you can make lexical bindings with the ‘lexical-let’
macro:
(lexical-let ((foo 1)) (defun foo-test () foo) (defun foo-inc () (incf foo))) => foo-inc (foo-test) => 1 (foo-test) => 1 (foo-inc) => 2 (foo-test) => 2
[Use `(eval-when-compile (require ‘cl))’ if you intend to distribute such code, to avoid runtime dependence on ‘cl’
in the compiled code.]
How can it be? ‘foo-test’
actually references a shared, hidden value slot. That’s because library cl uses macro hackery to simulate lexical binding. Examine it yourself:
(with-output-to-temp-buffer (pp (symbol-function 'foo-test))) => (lambda (&rest --cl-rest--) (apply '(lambda (G58033) (symbol-value G58033)) '--foo-- --cl-rest--)) nil
Note that this isn’t the same thing as actually having lexical variables in the language.
It’s also possible to use a macro to facilitate writing higher-order functions using lexical closures. First, let’s look at a simple example of a higher-order function using ‘lexical-let’
:
(defun compose (f g) (lexical-let ((f f) (g g)) (lambda (x) (funcall f (funcall g x)))))
It is a chore to write the ‘lexical-let’
part of it, but ‘defmacro’
can help.
;; Defun with lexically-scoped parameters. Could also be called ;; lexical-defun. (defmacro lexdef (name args &rest body) `(defun ,name ,args (lexical-let ,(mapcar (lambda (arg) (list arg arg)) (filter (lambda (a) (not (equal a '&rest))) args)) ,@body)))
Now we can write:
(lexdef compose (f g)
(lambda (x)
(funcall f (funcall g x))))
Our macro can also help us write a higher-order function that does currying, i.e., making a new function from ‘f’
by filling in some of ‘f’
s arguments and allowing the rest to be provided later.
(lexdef curry (f &rest args) (lambda (&rest more-args) (apply f (append args more-args)))) (set 'add1 (curry '+ 1)) (assert (= (funcall add1 2) 3))
See also WikiPedia:Scope (programming)