Real (Not Fake) Closures in Emacs 24.
Although Emacs 24 has lexical scooping when the variable lexical-binding has value t, the defun special form doesn’t work properly in lexically bound contexts (at least not in Emacs 24.2.1.) This makes it difficult, but not impossible, to define real (not fake) closures. For example:
(let ((counter 0))
(defun counting ()
(setq counter (1+ counter))))
will not work as expected because the symbol counter in the defun will be bound to the global variable of that name, if there is one, and not the lexical variable define in the let. When the function counting is called, if the global variable doesn’t, exist then it will obviously fail. Hoever if there is such a global variable it be updated, which is probably not what was intended and could be a hard to trace bug since the function might appear to be working properly.
The byte compiler does give a warning if you use defun in this way and presumably the issue will be addressed in some future version of Emacs, but until then the following macro can be used:
(defmacro defun** (name args &rest body)
"Define NAME as a function in a lexically bound context.
Like normal `defun', except that it works correctly in lexically
bound contexts.
\(fn NAME ARGLIST [DOCSTRING] BODY...)"
(let ((bound-as-var (boundp `,name)))
(when (fboundp `,name)
(message "Redefining function/macro: %s" `,name))
(append
`(progn
(defvar ,name nil)
(fset (quote ,name) (lambda (,@args) ,@body)))
(if bound-as-var
'nil
`((makunbound `,name))))))
If you define counting as follows:
(let ((counter 0))
(defun** counting ()
(setq counter (1+ counter))))
it will work as expected and update the lexically bound variable count every time it is invoked, while returning the new value.
CAVEAT: The macro will not work properly if you try to defun** a function with the same name as one of the lexically bound variables. I.e if you do something like:
(let ((dont-do-this 10))
(defun** dont-do-this ()
.........
.........))
I can’t imagine anyone actually doing that but it was worth a mention.
Note: I have named the macro defun** so that it doesn’t clash with the macro defun* in the cl package, however it doesn’t depend in any way on that package.