21

Suppose I have an Emacs lisp buffer that contains:

(defvar foo 1)

If I call eval-last-sexp or eval-buffer, foo is bound to 1. If I then edit this buffer to:

(defvar foo 2)

eval-last-sexp and eval-buffer do not re-execute this line, so foo is still 1.

This is particularly challenging when there are multiple such statements and I have to track down which lines are not being re-evaluated.

I looked at just restarting Emacs and then (require 'foo), but then I have to be careful to avoid loading any older .elc files.

How can I be absolutely, positively sure that the variables and functions defined in the current file are in the same state as loading code afresh in a new Emacs instance?

  • You cannot be "absolutely, positively sure that Emacs is in a state that is the same as loading the code afresh in a new Emacs instance" without doing just that. If you want to be sure only wrt this and other global variables, then you can remove their values using makunbound and then re-evaluate the code in the buffer. – Drew Oct 17 '14 at 21:30
  • Sure, side effects like (silly code) (incf emacs-major-version) I can live with happening repeatedly. I'm interested in hacking on code with lots of defvar forms. – Wilfred Hughes Oct 17 '14 at 21:36
29

As explained in other answers, evaluating a defvar form using eval-last-sexp does not reset the default value.

Instead, you can use eval-defun (bound to C-M-x in emacs-lisp-mode by default), which implements the behaviour you want as a special exception:

If the current defun is actually a call to defvar or defcustom, evaluating it this way resets the variable using its initial value expression even if the variable already has some other value. (Normally defvar and defcustom do not alter the value if there already is one.)


If you need to evaluate the full contents of a buffer, you can write a function that walks the top-level forms in turn and calls eval-defun on each. Something like this should work:

(defun my/eval-buffer ()
  "Execute the current buffer as Lisp code.
Top-level forms are evaluated with `eval-defun' so that `defvar'
and `defcustom' forms reset their default values."
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (while (not (eobp))
      (forward-sexp)
      (eval-defun nil))))
  • 5
    This is the answer. No need for fake defvars or extra setqs. Just use eval-defun instead of eval-last-sexp . You can even write a function that calls eval-defun on every form in the buffer, and use it instead of eval-buffer. – Malabarba Oct 17 '14 at 19:06
  • 1
    @Malabarba This post falls far short of answering the question. Use eval-defun instead of eval-last-sexp, sure, but the difficulty is for eval-buffer. – Gilles Oct 17 '14 at 21:17
  • @Gilles yes, you're right. I added a tentative implementation of @Malabara's idea of calling eval-defun on every top-level form in the buffer. – ffevotte Oct 17 '14 at 21:41
  • 1
    This approach does not seem to work if the defvar is not inside a defun. Example: (progn (defvar foo "bar")). – Kaushal Modi Mar 13 '15 at 15:01
  • 2
    @kaushalmodi The latter examples that you cite (variables storing regular expressions) look a lot like candidates for defconst (which is always re-evaluated). There's recently been a very enlightening post on this topic in endless parentheses – ffevotte Mar 13 '15 at 21:07
5

Like the other answers say, this is just the way defvar works, but you can get around it, this is elisp after all.

You can temporarily redefine how defvar works if you'd like and during that time, reload the packages you'd like to reset.

I wrote a macro where during the evaluation of the body, defvars values will always be reevaluated.

(defmacro my-fake-defvar (name value &rest _)
  "defvar impersonator that forces reeval."
  `(progn (setq ,name ,value)
          ',name))

(defmacro with-forced-defvar-eval (&rest body)
  "While evaluating, any defvars encountered are reevaluated"
  (declare (indent defun))
  (let ((dv-sym (make-symbol "old-defvar")))
    `(let ((,dv-sym (symbol-function 'defvar)))
       (unwind-protect
           (progn
             (fset 'defvar (symbol-function 'my-fake-defvar))
             ,@body)
         (fset 'defvar ,dv-sym)))))

Example Usage:

file_a.el

(defvar my-var 10)

file_b.el

(with-forced-defvar-eval
  (load-file "file_a.el")
  (assert (= my-var 10))
  (setq my-var 11)
  (assert (= my-var 11)
  (load-file "file_a.el")
  (assert (= my-var 10))

Note: This this should only be used for the purpose of reevaluating defvars, as it just ignores docstrings when reevaluating. You can modify the macro to support re-evaluating that applies docstrings as well, but I will leave that up to you.

In your case you could do

(with-forced-defvar-eval (require 'some-package))

But know what those who write elisp do so expecting defvar to work as specified, it could be they use defvar to define and setq in some init function to specify the value, so you may end up nil'ing variables you don't intend but this is probably rare.

Alternative Implementation

Using this you can just redefine defvar globally and control whether or not it will set the symbol's value to the INIT-VALUE arg even if the symbol is defined by changing the value of the new defvar-always-reeval-values symbol.

;; save the original defvar definition
(fset 'original-defvar (symbol-function 'defvar))

(defvar defvar-always-reeval-values nil
  "When non-nil, defvar will reevaluate the init-val arg even if the symbol is defined.")

(defmacro my-new-defvar (name &optional init-value docstring)
  "Like defvar, but when `defvar-always-reeval-values' is non-nil, it will set the symbol's value to INIT-VALUE even if the symbol is defined."
  `(progn
     (when defvar-always-reeval-values (makunbound ',name))
     (original-defvar ,name ,init-value ,docstring)))

;; globally redefine defvar to the new form
(fset 'defvar (symbol-function 'my-new-defvar))
  • 1
    I'm not sure redefining the behaviour of defvar is a good idea: there are several different possible uses of defvar, with slightly different semantics. For example, one use your macro doesn't account for is the (defvar SYMBOL) form, which is used to tell the byte-compiler about the existence of a variable without setting a value. – ffevotte Oct 17 '14 at 19:07
  • If you absolutely need to redefine defvar with a macro, you would probably be better off prefixing the original defvar form with a makunbound, rather than replacing it by setq. – ffevotte Oct 17 '14 at 19:11
  • Yes, it is a terrible idea, and should only be used for things like reevaluting the defvars of a loaded package in your scratch buffer, you should never ship something like this. – Jordon Biondo Oct 17 '14 at 19:12
  • @Francesco also you are right about the makunbound version, I had implemented that but strayed away from the idea, I have put that code on my answer as an alternative. – Jordon Biondo Oct 17 '14 at 19:15
3

The defvar is being evaluated and doing exactly what you've specified. However, defvar only sets an initial value:

The optional argument INITVALUE is evaluated, and used to set SYMBOL, only if SYMBOL's value is void.

So to achieve what you want you would either need to unbind the variable before re-evaluating, e.g.

(makunbound 'foo)

or use setq to set the value, e.g.

(defvar foo nil "My foo variable.")
(setq foo 1)

If you don't need to specify a docstring here you can skip the defvar altogether.

If you really want to use defvar and automatically unbind this, you will need to write a function to find defvar calls in the current buffer (or region, or last sexp, etc); call makunbound for each one; and then do the actual eval.

  • I was off playing with an eval-buffer wrapper that would unbind everything first, but @Francesco's answer about eval-defun is really what you want. – glucas Oct 17 '14 at 19:22
1

The following macro was created by tracing eval-defun to its supporting functions and modifying it so that it is no longer necessary to evaluate a region of a particular buffer. I needed help in the related thread Converting an expression to a string, and @Tobias came to the rescue -- teaching me how to convert the imperfect function into a macro. I don't think we need eval-sexp-add-defvars to precede elisp--eval-defun-1, but if someone thinks that is important, please let me know.

;;; EXAMPLE:
;;;   (defvar-reevaluate
;;;     (defvar undo-auto--this-command-amalgamating "hello-world"
;;;     "My new doc-string."))

(defmacro defvar-reevaluate (input)
"Force reevaluation of defvar."
  (let* ((string (prin1-to-string input))
        (form (read string))
        (form (elisp--eval-defun-1 (macroexpand form))))
    form))
0

The problem is not that the line is not getting re-evaluated. The problem is that defvar defines a variable and its default value. If a variable already exists, then changing its default value does not modify the current value. Unfortunately, I think you will need to run a setq for every variable whose value you wish to update.

This may be overkill, but you could update your file like this if you want to be able to easily update foo to its new default value.

(defvar foo 2)
(setq foo 2)

but that requires that you maintain the default value in two places in your code. You could also do this:

(makunbound 'foo)
(defvar foo 2)

but if there is a chance that foo is declared elsewhere you may have some side effects to deal with.

  • That's difficult when trying to test changes to a complex mode. I'd rather not change the code. eval-defun treats defvar specially, so surely there's something similar for whole buffers? – Wilfred Hughes Oct 17 '14 at 18:49
  • @WilfredHughes I'm not sure what you mean by "something for whole buffers." You want a single function that will makunbound any variables declared in the current buffer, and then re-evaluate it? You could write your own, but I don't think that there is an out-of-the-box function for this. EDIT: Never mind, I get what you are saying. An eval-defun that works on the whole buffer. It looks like @JordonBiondo has your solution for that. – nispio Oct 17 '14 at 18:53
  • No. The problem is lack of re-evaluation: defvar does nothing if the variable already has a value (as its doc says: The optional argument INITVALUE is evaluated, and used to set SYMBOL, only if SYMBOL's value is void.). The problem is not that defvar changes the default value and not the current value. (defvar a 4) (default-value 'a) (setq a 2) (default-value 'a); then C-x C-e after the defvar sexp; then (default-value 'a). C-x C-e, eval-region, and the like on a defvar sexp do not change the default value. – Drew Oct 17 '14 at 20:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.