Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a .emacs file be made idempotent?

No matter how many times I reload my .emacs file,

M-x load-file RET ~/.emacs RET

I want the results to be the same as the first time. I want to make my .emacs file be idempotent.

Motivation

I know I can surgically evaluate a region (C-c C-r), a defun (C-M-x), or the last sexp (C-x C-e). I often take such a more refined approach when making small changes. However, when re-working a .emacs file, I sometimes want to check results of the change conclusively by reloading the entire .emacs file. Restarting emacs each time gets old quick, especially when doing major .emacs housekeeping.

Specific Steps

What specific steps must I take to update my .emacs file to replace non-idempotent operations with idempotent ones?

For example,

  1. Search for "-hook" and replace direct additions to hooks with calls to add-hook, which will not re-add a function to the hook if already there.
  2. Replace toggling of any flags with direct setting or clearing. Beware of ?? in particular.
  3. ...

A comprehensive check-and-correct list would be ideal, but any key individual checks that occur to you would be helpful as well.

like image 956
kjhughes Avatar asked Dec 06 '22 01:12

kjhughes


1 Answers

I don't know as it's possible to ensure this completely, as most .emacs files depend on libraries which may not have idempotent initialization routines. However, there are a few useful tricks to reduce problems:

  1. Use named functions for add-hook, and keybindings instead of anonymous functions. For add-hook in particular, this allows it to swap out the existing reference.

  2. Careful use of defvar, by default the body is only evaluated if the variable is undefined. C-M-x on a defvar will re-eval the body, but eval-buffer will not if the variable is already initialized.

  3. Careful use of (quote function) instead of function to reference a named function instead of the value of the function. See Anonymous Functions for more advanced discussion about this.

  4. Remember that require will only load the corresponding library the first time it is executed, it will not re-eval on repeated calls as load does. Autoload also uses require to load the corresponding library.

  5. Prefer add-to-list instead of cons to only add an element if it doesn't exist.

  6. For older mode activation, make sure to use (mode-name-mode t) to activate instead of the toggle function. Likewise for turn-on- minor mode functions instead of the mode toggle.

  7. Guard blocks that do have side effects if executed repeatedly. In particular for server mode, (unless (server-running-p) (server-start)), and similar guards for installing packages.

  8. Being careful about side effects in eval-after-load or custom mode hooks. Remember the default mode hooks run when a mode is first enabled, and on each subsequent buffer, but will not rerun in existing buffers when the hook function is modified. eval-after-load is less likely to trip things up, it's still important to remember when it's evaluated.

  9. Related to #2, makunbound may be useful if a chain of vars that depend on each other need to be re-evaluated, as it will force the defvar to always execute on evaluation of the file.

Running eval-buffer on an init file should be as idempotent as possible, but it's important to remember that emacs lisp is fond of side effects and state. While it's possible to ameliorate this to some extent, re-evaling init will never return emacs to the state it was when it first started.

like image 144
dgtized Avatar answered Jan 09 '23 05:01

dgtized