(lispref.info)Cleanups


Prev: Errors Up: Nonlocal Exits

Cleaning Up from Nonlocal Exits
-------------------------------

   The `unwind-protect' construct is essential whenever you temporarily
put a data structure in an inconsistent state; it permits you to ensure
the data are consistent in the event of an error or throw.

 - Special Form: unwind-protect BODY CLEANUP-FORMS...
     `unwind-protect' executes the BODY with a guarantee that the
     CLEANUP-FORMS will be evaluated if control leaves BODY, no matter
     how that happens.  The BODY may complete normally, or execute a
     `throw' out of the `unwind-protect', or cause an error; in all
     cases, the CLEANUP-FORMS will be evaluated.

     Only the BODY is actually protected by the `unwind-protect'.  If
     any of the CLEANUP-FORMS themselves exit nonlocally (e.g., via a
     `throw' or an error), it is *not* guaranteed that the rest of them
     will be executed.  If the failure of one of the CLEANUP-FORMS has
     the potential to cause trouble, then it should be protected by
     another `unwind-protect' around that form.

     The number of currently active `unwind-protect' forms counts,
     together with the number of local variable bindings, against the
     limit `max-specpdl-size' (Note: Local Variables.).

   For example, here we make an invisible buffer for temporary use, and
make sure to kill it before finishing:

     (save-excursion
       (let ((buffer (get-buffer-create " *temp*")))
         (set-buffer buffer)
         (unwind-protect
             BODY
           (kill-buffer buffer))))

You might think that we could just as well write `(kill-buffer
(current-buffer))' and dispense with the variable `buffer'.  However,
the way shown above is safer, if BODY happens to get an error after
switching to a different buffer!  (Alternatively, you could write
another `save-excursion' around the body, to ensure that the temporary
buffer becomes current in time to kill it.)

   Here is an actual example taken from the file `ftp.el'.  It creates
a process (Note: Processes.) to try to establish a connection to a
remote machine.  As the function `ftp-login' is highly susceptible to
numerous problems which the writer of the function cannot anticipate,
it is protected with a form that guarantees deletion of the process in
the event of failure.  Otherwise, Emacs might fill up with useless
subprocesses.

     (let ((win nil))
       (unwind-protect
           (progn
             (setq process (ftp-setup-buffer host file))
             (if (setq win (ftp-login process host user password))
                 (message "Logged in")
               (error "Ftp login failed")))
         (or win (and process (delete-process process)))))

   This example actually has a small bug: if the user types `C-g' to
quit, and the quit happens immediately after the function
`ftp-setup-buffer' returns but before the variable `process' is set,
the process will not be killed.  There is no easy way to fix this bug,
but at least it is very unlikely.


automatically generated by info2www