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:
(let ((buffer (get-buffer-create " *temp*")))
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
(let ((win nil))
(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