Table of Contents
This article is a bit long. One may skip sections after the
- - - part.
Invasion of local variables is something that might happen when
- an emacs lisp file uses
defconstto declare a global special variable and
- another emacs lisp file happens to use a local variable of the same name as the global special variable from the other emacs lisp file.
What happens is that the behavior of the former file’s code may become unreliable, although not always. It is as if the former file is being invaded by the local variable. The other way around is invasion of special variables.
1. some simple example
This example is adopted from an example of “binding a special variable by accident” in Nikodemus’ Common Lisp FAQ.
Say there is an Emacs package
foo.el, written by Francesca, which declares a special variable
foo-string which may be a user option that controls the behavior of some features of
foo.el or it may be some important buffer-local variable used by
foo.el. Say there is also an Emacs package
bob.el, written by Bob, which defines a function that happens to use
baz-string as its local variable names. For example
(defun bob-do-something-with-three-strings (foo-string bar-string baz-string) (bob-dosomething foo-string) (bob-do-other-thing) (bob-dosomething bar-string) (bob-do-other-thing) (bob-dosomething baz-string))
bob-dosomething calls some other function from yet another package which in turn calls some other function from yet another package and so on and in the end it happens to call one of the functions from
foo-do-magic, that relies on the value of
foo-string as special variable. That call to
foo-do-magic won’t do what it is intended to do. That is because
bob-do-something-with-three-strings is binding the special variable
foo-string by accident. A local variable from Bob’s
bob.el is invading Francesca’s
2. what Bob can do (full measures)
What can Bob do to prevent his emacs lisp file
bob.el from accidentally invading other emacs lisp files? There are many approaches.
One approach is to always give green names (i.e. names without hyphen in them) to all local variables. This prevents invading because by convention special variables from other emacs lisp files are supposed to have yellow names (i.e. names with a hyphen in them).
There are a few built-in special variables with green names and you should avoid those names as well.
Another approach is to prefix every local variable name with a dollar sign. It’s unlikely for a special variable from some package to have a name that starts with a dollar sign (unless a package’s name starts with a dollar sign).
- - -
4. What Bob can do (half measures)
Maybe Bob doesn’t like either of the two approaches. Does byte compilation eliminate accidental invasion? For that, the same issues raised in the relevant section from the article on nvasion of special variables apply here as well.
What if Bob just check the list of all packages that
bob.el depends on and then stay away from prefixes those packages use? He can do that and that helps reduce chance of invasion, but it wouldn’t completely reduce the chance to zero because Emacs Lisp is a dynamic programming language. For example, if one of the packages
foo.el depend on invokes a function from org-mode which happens to run the hook org-export-filter-TYPE-functions, or if a user add advices to some of the packages, then it may end up calling a function not in the dependency list of
5. what Francesca can do
Maybe it shouldn’t be Francesca’s responsibility. Nevertheless, there are things she can do to reduce chance of her package being invaded. For example, she may choose a prefix for special variables that is not too simple.
Maybe she could mostly declare lexical global variables instead of special variables, and make sure that the few remaining special variables to have a name that is unlikely to be used as local variable names by others. This approach has a problem that lexical globals is not officially supported in Emacs. I haven’t tested to see if they work nicely as buffer local variables or user options. Maybe they work, but Francesca still would be relying on undocumented features of Emacs. The fact that
setq can make a lexical global is not documented, nor is the function
internal-make-var-non-special documented, which is a function used by Emacs during startup to make
6. comparison with invasion of special variables
Invasion of special variables can happen only when lexical scoping or lexical closures are involved, unlike invasion of local variables.