31

In C there is the magic variable __func__ that holds the current function name. In Bash, there is an array FUNCNAME holding the names of all functions in the calling stack !!!

Is there a similar thing in Emacs Lisp? Or any simple way for a function to have access to its name?

I have not found any answer in the Emacs Lisp manual (chapter 12 on Functions or index of variables and functions and ..)

4
  • 2
    What do you actually need that for?
    – user227
    Commented Oct 20, 2014 at 14:27
  • 2
    It's not exactly a magic variable -- it's a pre-processor definition inserted by some compilers. Commented Jan 15, 2015 at 21:46
  • @SeanAllred: FUNCTION is non standard, func exists in C99 / C++11. Similar LINE and FILE are standard.
    – Krazy Glew
    Commented Mar 13 at 22:21
  • 1
    @user227: Q: How often have you seen or written code like (defun foo () ... (message "debug in foo") ...)? Q: how often have you seen (defun foo () ... (message "debug in bar") ...) because somebody cut and pasted or change the name of a function? A: things like func, FILE, and LINE are pretty much a BKM in language design by now.
    – Krazy Glew
    Commented Mar 13 at 22:26

3 Answers 3

26

Updated answer with expansion time lookup:

I said in my original answer that there may be a way to do this at expansion/compile time instead of run time to give better performance and I finally implemented that today while working on my answer for this question: How can I determine which function was called interactively in the stack?

Here is a function that yields all current backtrace frames

(defun call-stack ()
  "Return the current call stack frames."
  (let ((frames)
        (frame)
        (index 5))
    (while (setq frame (backtrace-frame index))
      (push frame frames)
      (incf index))
    (remove-if-not 'car frames)))

Using that in a macro we can look up the expansion stack to see what function definition is being expanded at the time and put that value right in the code.

Here is the function to do the expansion:

(defmacro compile-time-function-name ()
  "Get the name of calling function at expansion time."
  (symbol-name
   (cadadr
    (third
     (find-if (lambda (frame) (ignore-errors (equal (car (third frame)) 'defalias)))
              (reverse (call-stack)))))))

Here it is in action.

(defun my-test-function ()
  (message "This function is named '%s'" (compile-time-function-name)))

(symbol-function 'my-test-function)
;; you can see the function body contains the name, not a lookup
(lambda nil (message "This function is named '%s'" "my-test-function"))

(my-test-function)
;; results in:
"This function is named 'my-test-function'"

Original Answer:

You can use backtrace-frame to look up the stack until you see frame that represents a direct function call and get the name from that.

(defun get-current-func-name ()
  "Get the symbol of the function this function is called from."
  ;; 5 is the magic number that makes us look 
  ;; above this function
  (let* ((index 5)
         (frame (backtrace-frame index)))
    ;; from what I can tell, top level function call frames
    ;; start with t and the second value is the symbol of the function
    (while (not (equal t (first frame)))
      (setq frame (backtrace-frame (incf index))))
    (second frame)))

(defun my-function ()
  ;; here's the call inside my-function
  (when t (progn (or (and (get-current-func-name))))))

(defun my-other-function ()
  ;; we should expect the return value of this function
  ;; to be the return value of my-function which is the
  ;; symbol my-function
  (my-function))

(my-other-function) ;; => 'my-function

Here I am doing the function name lookup at runtime though it is probably possible to implement this at a macro that expands directly into the function symbol which would be more performant for repeat calls and compiled elisp.

I found this information while trying to write a sort of function call logger for elisp which can be found here in it's incomplete form, but it might be useful to you. https://github.com/jordonbiondo/call-log

2
  • Thanks for the code. This solves my problem and I'll accept it in a few days unless someone give us the some sort of "current-function-name" variable that is part of the debugger you hint at.
    – phs
    Commented Oct 18, 2014 at 7:38
  • By the way, it does not seem to work when a defun is enclosed by eval-and-compile, i.e. it returns nil. Commented Dec 9, 2018 at 23:41
8

For interactive functions, i.e., commands, you can use the variable this-command, or safer, real-this-command. The difference being that when you write your own functions, you can explicitly change the value of this-command. Mostly this is done to play tricks with last-command related to repeating commands. You shouldn't (can't?) do this with real-this-command. It will always be the name of the current command.

I'm not aware of an equivalent for non-interactive functions.

2
  • 4
    It's important to note that this-command and real-last-command are not at all like __func__. For instance if command A calls command B which prints this-command it will print command A, not B, also this does not work at all for functions. Commented Jan 15, 2015 at 22:10
  • 1
    @JordonBiondo Agreed. I did note that it doesn't work for functions. phs didn't give us his context, so I guessed that this might be good enough for his application. Your answer is more robust, no question.
    – Tyler
    Commented Jan 16, 2015 at 19:50
0

Here are some updates which work with emacs 29+. It uses cl-incf, cl-remove-if-not, cl-third and cl-find-if. As of emacs 27, third was deprecated in favor of cl-third and staring with emacs 29, the use of cl- is mandated.

(require 'cl)
(require 'cl-lib)

(defun call-stack ()
  "Return the current call stack frames."
  (let ((frames)
        (frame)
        (index 5))
    (while (setq frame (backtrace-frame index))
      (push frame frames)
      (incf index))
    (remove-if-not 'car frames)))


(defmacro compile-time-function-name ()
  "Get the name of calling function at expansion time."
  (symbol-name
   (cadadr
    (cl-third
     (cl-find-if (lambda (frame) (ignore-errors (equal (car (cl-third frame)) 'defalias)))
              (reverse (call-stack)))))))
'''
1
  • 1
    Please make the answer self-contained. (And at least "above code" doesn't mean anything because the order of the answers displayed can change - above can change to below, and there might be 14 answers...)
    – Drew
    Commented Sep 1 at 21:15

Your Answer

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

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