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 make
the data consistent again 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.
If the BODY forms finish normally, `unwind-protect' returns the
value of the last BODY form, after it evaluates the CLEANUP-FORMS.
If the BODY forms do not finish, `unwind-protect' does not return
any value in the normal sense.
Only the BODY is protected by the `unwind-protect'. If any of the
CLEANUP-FORMS themselves exits nonlocally (via a `throw' or an
error), `unwind-protect' is _not_ guaranteed to evaluate the rest
of them. If the failure of one of the CLEANUP-FORMS has the
potential to cause trouble, then protect it with 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 again in time to kill it.)
Emacs includes a standard macro called `with-temp-buffer' which
expands into more or less the code shown above (Note:Current Buffer).
Several of the macros defined in this manual use `unwind-protect' in
this way.
Here is an actual example derived from an FTP package. 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 that 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 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.