Copyright (C) 2000-2012 |
GNU Info (elisp)CleanupsCleaning 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. automatically generated by info2www version 1.2.2.9 |