ELisp: “defvar” Doesn't Override

By Xah Lee. Date: . Last updated: .

there's this annoying problem in elisp. “defvar” does not override if the variable already has a value.

for example, run this:

(defvar yy 4 "DOCSTRING")
(defvar yy 3 "DOCSTRING")
(message "%d" yy)

the result is still 4.

what this means is that if you are actively developing a package, you can't reload your file and expect it to work.

The emacs behavior is documented:

(defvar SYMBOL &optional INITVALUE DOCSTRING)

…

The optional argument INITVALUE is evaluated, and used to set SYMBOL,
only if SYMBOL's value is void.  If SYMBOL is buffer-local, its
default value is what is set; buffer-local values are not affected.
If INITVALUE is missing, SYMBOL's value is not set.

Solution

here's a way to avoid the problem. When you write a mode, it's better to give the initial value of “nil” when using “defvar”, then set it immediately after it. Like this:

(defvar yy nil "DOCSTRING")
(setq yy 3 )

this way, when reloading, the new value will take place.

defvar vs defcustom

2013-03-18 Wolfgang Rupprecht [https://plus.google.com/114566345864337108516/posts] and Jack Donohue told me that the reason it's that way because users might set the var in their init file so that reloading a mode won't over-ride user's customization.

in the end, i think whether you should just use defvar or use setq afterward depends on what you are using the variable for. Modern elisp probably should use defcustom for vars for users to set.