EmacsInternVsMakeSymbol

By admin
Suppose, not hypothetically, that for some reason you’re trying to create a

GNU
ORG

Emacs

ELisp
ORG

macro that defines a function, and for your sins you don’t want to directly specify the name of your new function. In my case, I want to create a bunch of functions with names of the form ‘mh-visit-<something>’, which all use mh-visit-folder to visit the (

N)MH
ORG

folder ‘+inbox/<something>’. Ordinary people using macros to create functions probably give the macro the full name of the new function, but here it’s less annoying if I can put it together in the macro.

(I will put the summary here: unless you know what you’re doing, use intern instead of make-symbol in situations where you’re making up symbols, like on the fly function definitions.)

If we passed in the name of our new function to be, I believe the resulting macro would be (without niceties like docstrings):

(defmacro make-visit-func (fname folder) `(defalias ‘,fname (lambda () (interactive) (mh-visit-folder ,(format "+inbox/%s" folder))))) ;; usage: (make-visit-func mh-visit-fred "fred")

(You might think we would use defun , but defun is actually a macro itself and defalias is the direct thing, as I understand it; see Defining functions.)

The ` and , bits are

Backquoting
PERSON

, which lets us create a quoted list of the code the macro will generate while splicing in some variables. The peculiar ‘,fname is (E)Lisp for the value of ‘ fname ‘ spliced in to the list but quoted instead of evaluated; ‘ fname ‘ itself is not a string but a symbol (also), which we have here because symbols are how functions get their (global) names.

(We don’t have to quote ‘ mh-visit-fred ‘ when we use the macro because macro arguments are effectively automatically quoted, by virtue of being unevaluated.)

If we’re going to use the folder name to create both the full folder and the name of our new function, we need to turn a string into a symbol. If you quickly scan the documentation on creating symbols, there are

two
CARDINAL

plausible

ELisp
ORG

functions to use, intern and make-symbol . The latter’s name certainly sounds like what we want, and if you aren’t an

ELisp
ORG

expert, you might rewrite our make-visit-func to use it, like so:

;; This doesn’t actually work, don’t copy it. (defmacro make-visit-func (folder) `(defalias ‘,(make-symbol (format "mh-visit-%s" folder)) (lambda () (interactive) (mh-visit-folder ,(format "+inbox/%s" folder))))) ;; usage: (make-visit-func "fred")

If you do this, you will spend some time being rather confused. Your macro will execute without errors and debugging approaches like macroexpand will give you a result that works when evaluated. If you change to using intern , this will work, so you actually want:

;; This does actually work, you can copy it. (defmacro make-visit-func (folder) `(defalias ‘,(intern (format "mh-visit-%s" folder)) (lambda () (interactive) (mh-visit-folder ,(format "+inbox/%s" folder)))))

What I believe is happening is caused by the following innocent seeming bit in the description of make-symbol , emphasis mine:

This function returns a newly-allocated, uninterned symbol whose name is name (which must be a string).

Normally, the symbols that serve as the name of functions are interned, making them both visible for later use and kept around by

ELisp
ORG

garbage collection. However, what make-symbol gives us is an unreferenced symbol object (with a name assigned to it), so when defalias connects our lambda to it to make it a function, it is still not visible or retained. As a result it disappears into a puff of smoke afterward; even if it hasn’t been literally garbage collected, there is no reference to it.

Evaluating the result of macroexpand worked, because it was the (more or less) list result and when evaluated back created a normal, interned symbol. Here it is:

(defalias ‘mh-visit-fred (lambda nil (interactive) (mh-visit-folder "+inbox/fred")))

(I’ve split this on

three
CARDINAL

lines for readability.)

Although ‘ mh-visit-fred ‘ came from ‘ make-symbol ‘, it is printed as text (well, its name is), and when read back to evaluate, it will be a normal interned string. This is one of the cases where the printed representation is not actually the read syntax for this value. I believe that the actual neurotically correct print syntax for ‘ make-symbol ‘s result is ‘ #: ‘. Although I believe

Emacs
ORG

accepts this as read syntax, I don’t know if current versions ever print this on output unless you try very hard.

(Having gone through this once, I’m writing it down so that if I ever do this sort of thing again I won’t have to re-learn this.)

PS: Since I am not an

Emacs
ORG

Lisp expert, it’s quite possible that there are better ways to do all of this macro.