Skip to content

[emacs-30.1] [helpful--edebug-p] Always returns nil: evaluated lambda now interpreted-function (not list)  #370

Description

@962554

Mon 13 Apr 2026 09:13:51 BST

package version
emacs GNU Emacs 30.2.50 (build 1, aarch64-apple-darwin25.3.0, Carbon Version 170 AppKit 2685.4) of 2026-03-16
helpful 20250408.334 (melpa)

;; Edebug replaces function source code with a sexp that has
;; edebug-enter', edebug-after' etc interleaved. This means the
;; function is interpreted, so `indirect-function' returns a list.

indirect-function was changed 2023 (line 2491).

The result is no longer a list, but an interpreted-function, so (consp (indirect-function sym)) will always return nil.

ELISP> (type-of (indirect-function 'helpful--edebug))
interpreted-function

@Wilfred Is there an alternative that'll allow helpful--edebug-p to function as before?

My version of helpful--edebug-p (uses aref suggestion for interpreted-function objects):

(defun helpful--edebug-p (sym)
  "Does function SYM have its definition patched by edebug?"
  (when (closurep (indirect-function sym))
    (let ((fn-def (aref (indirect-function sym) 1)))
      ;; Edebug replaces function source code with a sexp that has
      ;; `edebug-enter', `edebug-after' etc interleaved. 
      ;; `indirect-function' returns an interpreted-function, inpectable with `aref`.
      (when (consp fn-def)
        (-let [fn-end (-last-item fn-def)]
          (and (consp fn-end)
               (eq (car fn-end) 'edebug-enter)))))))

Investigation

When edebug is turned on, helpful--edebug-p ((consp fn-def)) always returns nil. This prevents the helpful-edebug-button from being updated to Disable edebug.

I've tested using edebug (both via the helpful-edebug-button and manually) on helpful--edebug (as you'll be familiar with what to expect). I've also included the Symbol Properties (as provided in the helpful page for helpful--edebug).

Results for (indirect-function 'helpful--edebug)

Before turning on edebug

ELISP> (indirect-function 'helpful--edebug)
#<subr helpful--edebug>

After turning on edebug

ELISP> (indirect-function 'helpful--edebug)
#f(lambda (button) [t] "Toggle edebug for the current symbol."
    (edebug-enter 'helpful--edebug (list button)
                  #'(lambda nil :closure-dont-trim-context
                      (edebug-after (edebug-before 0) 4
                                    (helpful--toggle-edebug
                                     (edebug-after (edebug-before 1) 3
                                                   (button-get
                                                    (edebug-after 0 2 button)
                                                    'symbol))))
                      (edebug-after (edebug-before 5) 6 (helpful-update)))))

ELISP> (consp (indirect-function 'helpful--edebug))
nil

Symbol properties

Symbol Properties
edebug
  (#<marker at 15435 in helpful.el> nil [76 100 118 127 128 131 147]
            (#<window 18 on *helpful function: helpful--edebug*> . 15435))
edebug-behavior
  edebug
edebug-coverage
  [edebug-unknown edebug-unknown edebug-unknown edebug-unknown edebug-unknown
                  edebug-unknown edebug-unknown]
edebug-freq-count
  [0 0 0 0 0 0 0]
function-history
  (nil #<subr helpful--edebug>)
ghost-edebug
  nil

After turning off edebug

ELISP> (indirect-function 'helpful--edebug)
#f(lambda (button) [t] "Toggle edebug for the current symbol."
    (helpful--toggle-edebug (button-get button 'symbol)) (helpful-update))

ELISP> (consp (indirect-function 'helpful--edebug))
nil

Symbol properties

Symbol Properties
edebug
  #<marker at 15435 in helpful.el>
edebug-behavior
  edebug
edebug-coverage
  [edebug-unknown edebug-unknown edebug-unknown edebug-unknown edebug-unknown
                  edebug-unknown edebug-unknown]
edebug-freq-count
  [0 0 0 0 0 0 0]
function-history
  ("/Users/m/.emacs.d/elpa/helpful-20250408.334/helpful.el"
   #[(button)
     ((edebug-enter 'helpful--edebug (list button)
                    #'(lambda nil :closure-dont-trim-context
                        (edebug-after (edebug-before 0) 4
                                      (helpful--toggle-edebug
                                       (edebug-after (edebug-before 1) 3
                                                     (button-get
                                                      (edebug-after 0 2 button)
                                                      'symbol))))
                        (edebug-after (edebug-before 5) 6 (helpful-update)))))
     (t) nil "Toggle edebug for the current symbol."]
   nil #<subr helpful--edebug>)
ghost-edebug
  (#<marker at 15435 in helpful.el> nil [76 100 118 127 128 131 147]
            (#<window 18 on *helpful function: helpful--edebug*> . 15435))

Found the following references for #f() notation:
Ref:

  1. https://stackoverflow.com/a/72561466
  2. https://www.gnu.org/software/emacs/manual/html_node/elisp/Special-Read-Syntax.html
  3. https://github.com/emacs-mirror/emacs/blob/5caab891b4541e2ad41d86472a8b256760092f16/etc/NEWS.30#L2001-L2015

Evaluating a 'lambda' returns an object of type 'interpreted-function'.
Instead of representing interpreted functions as lists that start with
either 'lambda' or 'closure', Emacs now represents them as objects
of their own 'interpreted-function' type, which is very similar
to 'byte-code-function' objects (the argument list, docstring, and
interactive forms are placed in the same slots).
Lists that start with 'lambda' are now used only for non-evaluated
functions (in other words, for source code), but for backward compatibility
reasons, 'functionp' still recognizes them as functions and you can
still call them as before.
Thus code that attempts to "dig" into the internal structure of an
interpreted function's object with the likes of 'car' or 'cdr' will
no longer work and will need to use 'aref' instead to extract its
various subparts (when 'interactive-form', 'documentation', and
'help-function-arglist' aren't adequate).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions