4

I accidentally unbound a built-in function (a subr) from its usual symbol. Is there a generic way to recover it?

Of course I could save my buffers and my session, exit Emacs and start another instance. That is, if the function I lost wasn't needed to save and exit. What can I do if I lose some really fundamental function such as write-region or get-buffer?

Drew
  • 75,699
  • 9
  • 109
  • 225
  • I'm not sure you can unbind functions defined in C code, did this actually happen to you, or is the question purely theoretical? If this was an ELisp function you could just reload the file where it is defined, well, guess you already knew that. – wvxvw Sep 21 '15 at 21:13
  • @wvxvw You can unbind almost any symbol. I think the only exceptions are `nil` and `t`. The built-in function still exists, of course, but if you unbind the symbol whose function slot is normally bound to it, how do you access it? And yes, I asked that because it happened to me, fortunately for a function that was easy to implement in a different way, but I wonder if there's a systematic way to recover. – Gilles 'SO- stop being evil' Sep 21 '15 at 21:25

1 Answers1

1

After accidentally losing write-region (there's some weird interaction between flet and advice that I don't understand), I added this code early in my .emacs. I save all the subroutines in a separate obarray, so as long as I don't lose both fset and defalias I should be able to recover.

;; Before anything else, keep a copy of all built-in functions. This
;; is not used during normal operation, only when I accidentally
;; unbind a primitive, e.g. due to ill-advised advice.
;; https://emacs.stackexchange.com/questions/16806/recover-a-built-in-function-that-i-accidentally-unbound
(defvar subr-backup-obarray
  (let ((backup-obarray (make-vector (length obarray) 0)))
    (mapatoms (lambda (symbol)
                (if (and (fboundp symbol) (subrp (symbol-function symbol)))
                    (fset (intern (symbol-name symbol) backup-obarray)
                          (symbol-function symbol)))))
    backup-obarray)
  "Backup of all built-in functions.")
(defalias 'subr-backup
  ;; Why this strange definition? This way we get a byte-compiled
  ;; object that doesn't contain any call to a function symbol, only
  ;; bytecode opcodes and subr objects.
  (byte-compile
   (let ((intern-soft (list 'funcall (symbol-function 'intern-soft)))
         (symbol-function (list 'funcall (symbol-function 'symbol-function)))
         (symbol-name (list 'funcall (symbol-function 'symbol-name)))
         (symbolp (list 'funcall (symbol-function 'symbolp))))
     `(lambda (name)
        (,@symbol-function
         (,@intern-soft (if (,@symbolp name) (,@symbol-name name) name)
                        subr-backup-obarray)))))
  "Return the backup of the built-in function (subr) originally bound to NAME.
NAME may be a string or symbol.
If a symbol that is normally bound to a built-in function has become unbound
or bound to another function, the original subr binding can be restored with
  (fset 'SYMBOL (subr-backup 'SYMBOL))
or (if SYMBOL has no `defalias-fset-function' property)
  (defalias 'SYMBOL (subr-backup 'SYMBOL))")
  • Nice! (I wrote just about the same code while trying to answer your question, but did not have the time to clean it up and post it. :-) ) – Constantine Feb 15 '16 at 18:20