0

Question

How do I run code before any void-function error is signaled? I have a feeling I can use advising for this, but I don't know what exactly I need to advise.

What I want to achieve

Before any void-function error is raised, I'd like emacs to try to load existing features that are likely to provide that function. For example, if the function evil-magit-init is called and is not already defined, I'd like emacs to check the load-path, notice that the feature evil-magit has a name that is a prefix for evil-magit-init, load it and check if evil-magit-init is defined and then, if it is, load evil-magit and then try calling evil-magit-init again. Essentially, this is an alternative to autoloading.

What I tried

As a model I looked towards auto-define, a package that tries to define non-existing functions that follow a pattern "on-the-fly". For example, it would take a function such as prog4 and define it based on what prog1 and prog2 do.

I tried to emulate this with the following:

(defun eval@try-load-feature (orig-fn &rest args)
  "Try to load feature that could contain function."
  (condition-case err
      (apply orig-fn args)
    (void-function
     (iter
      (with (fname (cadr err)))
      (initially (message "Triggering advice with %s!!!" (cadr err)))
      (for feature (xl-possible-features fname))
      (require feature)
      (when (fboundp fname)
       (message "Autoloading %s..." feature)
       (return (apply orig-fn args)))
      (else (signal (car err) (cdr err)))))))
(advice-add 'eval :around (function eval@try-load-feature) nil)

;; (xl-possible-features 'evil-magit-init) => (evil-magit evil)
(defun xl-possible-features (fn)
  "Return a list of possible features available for FN"
  (loopy (with (fname (symbol-name fn)))
     (list path load-path)
     (expr base (f-base path))
     (expr feature (intern base))
     (when (s-prefix-p base fname)
       (collect possible feature))
     (finally-return (seq-sort-by (-compose #'length #'symbol-name) #'> possible))))

What Actually Happened

My solution only caught the void-function error with functions that seemed to use eval. Such as eval-last-sexp. However, it does not work for void-function errors from forms not evaluated in a buffer. As I mentioned I'd like to intercept void-function errors raised from anywhere.

3
  • May I ask your motivation for this? It just sounds like a bad idea to me. If this is possible at all, I suspect it's going to introduce substantial inefficiencies. I would expect that by the time Emacs is raising a void-function error, the opportunity to call a function has passed -- and if that's the case, you'd instead need to act before every single function call (if that's even possible to do) to test whether or not that error is going to happen...
    – phils
    Jun 7, 2021 at 0:38
  • My motivation is not to have to use Emacs's autoload system. Instead of relying on well-placed autoload cookies and having to maintain an autoloads file, I wanted to explore the possibility of relying on package prefixes. As for the efficiences, I don't necessarily think it would be inefficient as this would only happen during void-function errors--my example demonstrates how I could do this when advising a single function. I agree that if I needed to act before every function call I'd run into problems, but that's not what I'm going for. Jun 7, 2021 at 2:09
  • I think you'll need to do this in C code.
    – phils
    Jun 8, 2021 at 0:48

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.