abo-abo
abo-abo

Reputation: 20342

Elisp: make symbol-function return the source?

Here's the setup:

(defun square (x)
  (* x x))
;; square
(symbol-function 'square)
;; (lambda (x) (* x x))
(byte-compile 'square)
;; #[(x) "\211_\207" [x] 2]
(symbol-function 'square)
;; #[(x) "\211_\207" [x] 2]

Is there a way to get the source (lambda (x) (* x x)) after square has been byte-compiled?

The two uses that I can think of are inlining the current function call and doing a debug-step-in.

I've tried messing with find-definition-noselect to get the source, but I wonder if there's a better way, because it sometimes raises

(error "Don't know where ... is defined")

Upvotes: 3

Views: 394

Answers (2)

Stefan
Stefan

Reputation: 28531

Emacs keeps track of which function name is defined in which file (this info is kept in load-history). To find the definition, Emacs looks in load-history and if the function is listed there, it looks for the corresponding source file and then in that file looks for something that looks like a likely definition of the function (using regexps). That's what find-definition-noselect does.

As for the source code, no in general Emacs does not keep the source definition. If you define the function with cl-defsubst, then the source is kept around, but otherwise it isn't. For Edebugging, having the source wouldn't help anyway (because Edebug needs not just the source cod but also the precise location of each sub-expression); for plain debugging the source is not really needed either (you can always click on the function's name to jump to the source); for inlining the source is not needed either (the byte-compiler can inline at the source-code level, indeed, but it can just as well inline at the byte-code level).

Upvotes: 2

user355252
user355252

Reputation:

There is no way to obtain the source of a function object. Byte compilation is no injective function, so you cannot revert it. Even disregarding macro expansion, there is no direct mapping from opcodes to Lisp expressions.

I do not see use cases for this anyway.

Debugging

To step into functions for debugging, navigate to its definition (i.e. find-definition) and instrument the definition for debugging (e.g. with edebug). That's the only way to reasonably debug Emacs Lisp functions. You can't use the contents of the function cell for debugging, because it's subject to macro expansion.

As such, the function cell may look completely different from the actual definition. If you find a bug in the function cell, you'll struggle to find the same bug in the actual function definition.

Inlining

For inlining, use macros or defsubst to define inline functions in Emacs Lisp. However, be careful to not accidentally expose these on the public interface of your library, since compile time inline functions impose a compile time dependency onto your library, so a dependent library needs to be recompiled for every release of your library. And since package.el doesn't support that yet, macros and substitutions can easily cause havoc.

Upvotes: -1

Related Questions