elisp: Cleanups

 
 10.6.4 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.  (Another more
 specific cleanup construct that is used only for changes in buffer
 contents is the atomic change group; SeeAtomic Changes.)
 
  -- Special Form: unwind-protect body-form cleanup-forms...
      ‘unwind-protect’ executes BODY-FORM with a guarantee that the
      CLEANUP-FORMS will be evaluated if control leaves BODY-FORM, no
      matter how that happens.  BODY-FORM 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 BODY-FORM finishes normally, ‘unwind-protect’ returns the value
      of BODY-FORM, after it evaluates the CLEANUP-FORMS.  If BODY-FORM
      does not finish, ‘unwind-protect’ does not return any value in the
      normal sense.
 
      Only BODY-FORM 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’ (SeeLocal Variables Definition of
      max-specpdl-size.).
 
    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*")))
        (with-current-buffer buffer
          (unwind-protect
              BODY-FORM
            (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-FORM happens to get an error after
 switching to a different buffer!  (Alternatively, you could write a
 ‘save-current-buffer’ around BODY-FORM, 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 (SeeCurrent Buffer
 Definition of with-temp-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 (SeeProcesses) 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.