The very unofficial .emacs home The very unofficial dotemacs home
emacs
Sections
home
what is this all about ?
customization basics
special topics
local dotfiles
dotfiles on the web
new and updated pages
useful sites and pages
search locally
EMacro
OS/2 Emacs
Special topics
dotfiles and custom
multiple Emacs and OS
errors in your dotfile
Latest Additions
local files:
John J. Glynn
David Jolley

linked files:


articles:


links:
The Emacs wiki

How to avoid errors in your dotfile

Did you ever add a new snippet of code to your .emacs and got an only partially loaded dotfile ? Half of your customizations gone with the wind ?
I've encountered this behaviour various times, and I didn't feel happy seeing this.

The best thing you can do, is to avoid errors in your dotfile, but how ?
Well, what about testing them before you add them to your dotfile ? There is noything mysterious about that, the only thing you have to do is to put them into a buffer and execute the statements. The *scratch* buffer is exactly for this.
Type your statements into this buffer and execute them by pressing C-x C-e after the last parenthesis of every form you want to test.
This way you do some kind of single step testing if you have more than one thing to evaluate. To shorten the procedure you can evaluate a complete region by entering M-x eval-region.

If all works fine and you don't see any errors, there is a chance that the code will also work in your dotfile.

Stop ! A chance ? Sorry, yes, only a chance.

Evaluating things in the *scratch* buffer means that you're already working with Emacs thus all things should be setup properly. All vars initialized, all the packages you use are available or waiting to be autoloaded.
Here are a few examples of what might happen in your dotfile:

  • Your code uses a function which can be autoloaded and it works in the *scratch* buffer. Add it to the top of your dotfile and it will fail because of the missing autoload.
  • You have setup a section for varaible customizing at the top of your dotfile. You set a variable of a package to a value which fits to your needs. The package is loaded at the end of your dotfile and sets the value back to the package default.
  • You already have customized the variable with customize. Same as above, your dotfile entry might be gone, but this is an other story.
The second and third example will not even produce an error in your dotfile, Emacs will happily do what you have told him to do. You'll only recognize it at the point where something doesn't work as expected.

That's not the case for the first example. The void symbol for the function is recognized as an error and Emacs will stop reading the dotfile.
Most of the time this is a wanted behavior, because this way you recognize that there is an error which should be corrected. On the other hand, there might be situations where this is unwanted, because you know that there might be an error. Using the same dotfile at work and at home but with different packages or flavours of Emacs available might be such a situation.
It would be nice to catch these errors without them breaking your dotfile.

Error recovery

Reviewing one of the dotfiles provided for publishing on the site I saw statements like this one:
;;; Display the time on modeline
(condition-case err
    (display-time)
  (error
   (message "Cannot display time %s" (cdr err))))
;;;
Hey, what is this guy doing there ?
Looks very interesting, a kind of try/catch for elisp ? Having checked it in the elisp manual, I saw that there is a possibility to protect the dotfile against bad code. Reading more and trying some statements I recognized that it is restricted to what is called a form. Hmm, beeing no elisp professional, but just a dumb c/c++ and java programmer, I've played a bit with it and saw that I can protect only what a c programmer would call a statement.
Not much :((
Playing a bit more with it, I found a possibility to do the test for a bigger block:
(defmacro try-and-error ()
  (setq tralala t)        ; will proceed as expecetd
  (setq bar tralali)      ; will fail if tralali is unknown
  (defun foo-mul (factor) ; even a defun is possible, but evaluates
    (* foo factor))       ; to its name, thus producing an error
                          ; because it's not defined if it is the
                          ; last entry in the macro
  nil                     ; to return something defined after the defun
                          ; as the result of the form 
)
(condition-case err
    (try-and-error)
  (error
   (setq message-log-max t)  ; if an error occurs, I'd like to see all messages
   (message "Ooops, try and error failed: %s" err)))
Adding the above to your dotfile will give you this message in your messages buffer:
Ooops, try and error failed: (void-variable tralali)
The rest of your dotfile is loaded as expected. You're able to work with your normal environment, even if the new things failed.

But hey, there are several drawbacks:
If you take a look at the defun, you'll recognize that it uses foo, which is not defined. The condition-case statement doesn't complain about this, the function is defined, not evaluated. Nevertheless, it is useless, the first execution will lead to a message like:
Symbol's value as variable is void: foo
The error strikes back :))
Btw.: A definition like the one above works in the same way if it is not protected by condition-case, so it makes no sense at all to protect it. It was only introduced to show what can be done.

More important is the fact that Emacs, stopping to read the rest of your dotfile if an error occurs, signals that there is something odd in your dotfile. You have to search for it, but you know that there is an error. Catching the error doesn't give you this kind of feedback. Loading of your dotfile proceedes as if nothing is wrong. You'll only recognize the error if you look into the messages buffer or see that the new features don't work.
If you don't do anything to catch the error, you'll get the message

Error in init file: Symbol's value as variable is void: tralali

Making it part of the load strategy

Lawrence Buja has mailed the following:

After my .emacs file grew too large to comprehend, I split it up into a number of different .el files grouping different functional areas Then I added safe-load function to continue loading the rest of the .el files if any of the .el files fails to load correctly. As you can see from the date on safe-load, it's been working fine for me for years.

---start of .emacs ----------snip---------------snip-----------snip-------------------

 (setq load-path (append '("/home/southern/emacs/fortran") load-path))
 (setq load-path (append '("/home/southern/emacs") load-path))

 (     load "safe-load"         nil t )  ; error trapping load function.
 (safe-load "defaults"          nil t )  ; emacs default variable settings.
 (safe-load "hooks"             nil t )  ; various mode hooks.
 (safe-load "tools"             nil t )  ; various tools and functions.
 (safe-load "my-keys"           nil t )  ; my ESC/Control key customizations.
 (safe-load "my-print"          nil t )  ; my print buffer & region commands.
 (safe-load "compress"          nil t )  ; uncompress when loading a .Z file.
 (safe-load "all"               nil t )  ; hide/expose text.
 (safe-load "echistory"         nil t )  ; system electric history package.
 (safe-load "ispell"            nil t )  ; system electric spell package.
 (safe-load "show-file-buffers" nil t )  ; Display all buffers that are visiting files.
 (safe-load "server-start"      nil t )  ; start emacsclient server
 (safe-load "solaris-keys"      nil t )  ; Solaris specific key bindings
 (start-server)
 (set-mark-command nil) 

---end   of .emacs ----------snip---------------snip-----------snip-------------------
---start of safe-load.el ----------snip---------------snip-----------snip-------------

;    
;     File:   /u3/ccmproc2/emacs/safe-load.el  (939 bytes) 
;     Date:   Tue Dec  1 09:26:25 1992
;     Author: Lawrence Buja <ccmproc2@sunny>
;    
(defvar safe-load-error-list ""
        "*List of files that reported errors when loaded via safe-load")

(defun safe-load (file &optional noerror nomessage nosuffix)
  "Load a file.  If error when loading, report back, wait for
   a key stroke then continue on"
  (interactive "f")
  (condition-case nil (load file noerror nomessage nosuffix) 
    (error 
      (progn 
       (setq safe-load-error-list  (concat safe-load-error-list  " " file))
       (message "****** [Return to continue] Error loading %s" safe-load-error-list )
        (sleep-for 1)
       nil))))

(defun safe-load-check ()
 "Check for any previous safe-load loading errors.  (safe-load.el)"
  (interactive)
  (if (string-equal safe-load-error-list "") () 
               (message (concat "****** error loading: " safe-load-error-list))))

---end   of safe-load.el ----------snip---------------snip-----------snip-------------

Conclusion

It's your decision:
  • Beeing forced to correct the error Emacs found for you
  • or to ignore it to have your environment beeing setup as usual and you beeing responsible to look for errors that might have occured.
All content copyright by the contributors. Website maintained with Emacs , wsmake and html-helper-mode
Emacs community logo by Daniel Lundin Last updated on Sat Jan 22 14:57:03 2005 by Ingo Koch