In the old days, Emacs had no support for lexical scope. I am wondering how people dealt with a particular pitfall of dynamic scope in those days.
Suppose Alice writes a command my-insert-stuff
which relies on the fp-repeat
function defined in fp.el
(which we suppose is a library providing lots of functions for functional programming written by Bob) and suppose fp-repeat
is for repeatedly calling a function many times.
Part of contents of init.el
from Alice:
(require 'fp)
(defun my-insert-stuff ()
(interactive)
;; inserts "1111111111\n2222222222\n3333333333" to current buffer
(dolist (i (list "1" "2" "3"))
(fp-repeat 10
(lambda ()
(insert i)))
(insert "\n")))
Part of contents of fp.el
from Bob:
(defun fp-repeat (n func)
"Calls FUNC repeatedly, N times."
(dotimes (i n)
(funcall func)))
Alice soon finds that her command doesn't work like she expects. That's because Alice's use of i
and Bob's use of i
collide. In the old days, what could Alice or/and Bob do to prevent this kind of collision from happening?
Maybe Bob could change the docstring to
"Calls FUNC repeatedly, N times.
Warning: Never use i, n, func in FUNC body as nonlocal variables."
Alice would have taken care to not use non-local variables in
lambda
bodies, being aware thatlambda
did not create lexical closures.In Emacs Lisp, this simple policy is actually sufficient to avoid most issues with dynamical scoping, because in the absence of concurrency, local
let
-bindings of dynamic variables are mostly equivalent to lexical bindings.In other words, Emacs Lisp developers of the “old days” (which are not so old given the amount of dynamically scoped Emacs Lisp still around) would not have written a
lambda
like that. They would not even have wanted to, because Emacs Lisp was not a functional language (and still isn't), thus loops and explicit iteration were often preferred over higher order functions.With regards to your specific example, Alice of the “old days” would just have written two nested loops.