3

intro

Sometimes I want to generate a function programmatically as opposed to defining one with defun. You may wondering why I'd want to do this. Well, it's complicated but just bear with me for a moment.

(defun void-defun (fn)
  (let ((name (gensym "void-defun-")))
    (eval
     `(progn
        (message "Created function: %S" name)
        (defun ,name ()
          (funcall #',fn))))
    name))

problem

When I test whether the function is bound with the following code, all is well.

(let ((fn (void-defun (lambda () 2))))
  (and (fboundp fn) (= 2 (funcall fn)) fn))
;; => void-defun-69

after the test

However, after evaluating this test code and calling the function (whose name I know from the *messages* buffer) I get a void-function error. I expected the function to be bound as indicated by my test. It is as if the function was bound temporarily for the execution of my test form then unbound again.

;; This 69 is just as an example of a name I could get.
(funcall #'void-defun-69)
;; => eval: Symbol’s function definition is void: void-defun-69

question

Why does this happen? And how can I avoid this?

2
  • 1
    Why don't you use macros to define functions programmatically? Why eval?
    – wasamasa
    Apr 16, 2020 at 6:33
  • The whole story is that I have a macro called defun! which is the same as defun except that after the docstring it is possible to supply keyword arguments such as (defun! fn () (:expire t) (:after message) (message "Just messaged")). This would result in a function that is an after advice to message and would unbind itself after its first call. I have wanted to call this macro via a function e.g. (void-defun (lambda () (message "hi") :expire t :after #'hi). I've heard it is not good practice to use eval. Before this I had (funcall (backquote (lambda () ...)) to avoid eval Apr 16, 2020 at 12:41

1 Answer 1

4

If you assign a function to an uninterned symbol, then naturally you won't find that function on the interned symbol of that name -- they are two completely independent objects.

Your void-defun is returning that uninterned symbol, and in your successful test you are capturing that symbol, so naturally you can successfully call its function.

In your unsuccessful test you are trying to use the function of the interned symbol by that name.

You may be looking for the intern function to obtain the interned symbol by the supplied name.

See also: C-hig (elisp)Creating Symbols

Your Answer

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

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