Invasion of local variables in Emacs Lisp

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 defvar, defcustom or defconst to 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 foo-string, bar-string, 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-dosomething bar-string)
  (bob-dosomething baz-string))

Suppose that 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.el, say 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 foo.el.

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).

3. - - -

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 bob.el.

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 argv and argi non-special.

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.

This entry was posted in Emacs, Lisp and tagged , . Bookmark the permalink.

1 Response to Invasion of local variables in Emacs Lisp

  1. Pingback: Differences between Common Lisp and Emacs Lisp | Yoo Box

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s