3

Let's consider a minimal example, I take org-narrow-to-subtree as a compiled function, under the hood it calls narrow-to-region, I add simple advice to it:

(defun bark (START END) (message "Bark!"))
(advice-add 'narrow-to-region :before #'bark)

If I call narrow-to-region interactively, the advice obviously works, but if I call org-narrow-to-subtree which in its turn calls (narrow-to-region), it behaves as if there was no advice.

If re-eval the function definition (the same source as the original, only defining it again instead of using the compiled version):

(defun org-narrow-to-subtree ()
  "Narrow buffer to the current subtree."
  (interactive)
  (save-excursion
    (save-match-data
      (org-with-limited-levels
       (narrow-to-region
    (progn (org-back-to-heading t) (point))
    (progn (org-end-of-subtree t t)
           (when (and (org-at-heading-p) (not (eobp))) (backward-char 1))
           (point)))))))

and call org-narrow-to-subtree again, the advice gets called normally.

  1. Why is that?
  2. How do I solve my problem then? How do I add an advice?
3
  • It'll probably involve a macro somewhere, if advice wasn't avaible when compiled it won't work. I'll check it later. – Muihlinn Dec 2 '20 at 9:02
  • 4
    narrow-to-region has its own byte code, 125, try (byte-compile (lambda () (narrow-to-region 1 10))), hence after compilation, the function is replaced by its byte code. – xuchunyang Dec 2 '20 at 9:23
  • I think @xuchunyang will be the quickest way to solve it, I'd say that calling your advised function inside two macros compiled before your advise existed are the culprit, so recompiling the function will make it work – Muihlinn Dec 2 '20 at 12:37
4

This (narrow-to-region) is the exact example covered by Chris Wellon's article The Limits of Emacs Advice. As @xuchunyang has already pointed out, the issue is that this function has its own byte code value, and hence advice does not work when the code is byte-compiled.

You should read the whole article, but I'll quote this:

It turns out narrow-to-region is so special — probably because it’s used very frequently — that it gets its own bytecode. The primitive function call is being compiled away into a single instruction. This means my advice will not be considered in byte-compiled code. Darnit. The same is true for widen (code 126).

2
  • Thanks @phils and @xuchunyang. Is it okay if I force a byte-recompilation of org upon initialisation of my package? Or it shall be separate question in this SE? – Daniel Vartanov Dec 6 '20 at 10:00
  • It's not clear to me why you're asking that, so maybe ask a separate question with all of the relevant details. – phils Dec 6 '20 at 10:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.