0

I'm trying to (funcall) a function reference I have in a plist.

(defun helper-get-filename ()
  "Argument Helper to get a filename."
  (read-file-name "-l <filename>: " "~/"))

(let ((plist  '(:flag "-l" :arg-helper #'helper-get-filename)))
  (funcall (plist-get plist  :arg-helper)))

However, Emacs debugger responds with:

Debugger entered--Lisp error: (invalid-function #'helper-get-filename)
  #'helper-get-filename()
  funcall(#'helper-get-filename)
  (let ((plist '(:flag "-l" :arg-helper #'helper-get-filename))) (funcall (plist-get plist :arg-helper)))
  eval((let ((plist '(:flag "-l" :arg-helper #'helper-get-filename))) (funcall (plist-get plist :arg-helper))) nil)
  elisp--eval-last-sexp(nil)
  eval-last-sexp(nil)
  eros-eval-last-sexp(nil)
  funcall-interactively(eros-eval-last-sexp nil)
  call-interactively(eros-eval-last-sexp nil nil)
  command-execute(eros-eval-last-sexp)

How is this done properly?

ocodo
  • 1,202
  • 11
  • 20
  • 1
    Does this answer your question? [How to evaluate the variables before adding them to a list?](https://emacs.stackexchange.com/questions/7481/how-to-evaluate-the-variables-before-adding-them-to-a-list) – NickD Jun 17 '22 at 13:18
  • Not specifically. But thanks for adding the reference. – ocodo Jun 17 '22 at 17:50

3 Answers3

1

So the correct answer is don't use quote - '

Instead backquote the list structure or use the list function.

Using list

(defun helper-get-filename ()
  "Argument Helper to get a filename."
  (read-file-name "-l <filename>: " "~/"))

(let ((plist (list :flag "-l" :arg-helper #'helper-get-filename)))
  (funcall (plist-get plist  :arg-helper)))

or for brevity use the backquote style. It will also keep the bytecode compiler happy and avoid a missing function reference at compile time.

(defun helper-get-filename ()
  "Argument Helper to get a filename."
  (read-file-name "-l <filename>: " "~/"))

(let ((plist `(:flag "-l" :arg-helper ,#'helper-get-filename)))
  (funcall (plist-get plist  :arg-helper)))
ocodo
  • 1,202
  • 11
  • 20
  • @terrytsao has the correct answer. as in the simplest, with the least line noise. Thanks again Terry. – ocodo Jun 17 '22 at 08:51
  • 1
    I prefer your answer, because `#'foo` is better than `'foo`, because the byte compiler can complain when `foo` is not known to be defined. – Greg Hendershott Jun 17 '22 at 12:58
1

It's because 'helper-get-filename is not a valid function name, helper-get-filename is. You are doubly quoting the function name.

Your code should have been:

(let ((plist '(:flag "-l" :arg-helper helper-get-filename)))
  (funcall (plist-get plist  :arg-helper)))

;;; or

(let ((plist (list :flag "-l" :arg-helper #'helper-get-filename)))
  (funcall (plist-get plist  :arg-helper)))

;;; Or backquote so 
;;; #' can keep the compiler happy.

(let ((plist `(:flag "-l" :arg-helper ,#'helper-get-filename)))
  (funcall (plist-get plist  :arg-helper)))
ocodo
  • 1,202
  • 11
  • 20
TerryTsao
  • 1,176
  • 4
  • 18
0

I could hold a reference to the function in the plist as a string and do:

(funcall (intern "helper-get-filename"))

That does make me cringe a little bit, and I'm sure there's a correct way to do this.

(And there is! The accepted answer has 2 good, and one best way, backquote the top level containing list and use ,#'helper-get-filename for the function reference in the example. You can evaluate any variable this way too to include their results in the list)

ocodo
  • 1,202
  • 11
  • 20
  • this answer should be downvoted. – ocodo Jun 17 '22 at 08:50
  • If you think it is not useful, you could delete it. – NickD Jun 17 '22 at 14:40
  • I think it's useful to record options i wouldn't recommend. – ocodo Jun 17 '22 at 17:44
  • There are way too many bad ways to do something, so recording them is probably not necessary and maybe even harmful. But I was just pointing out the option: use it only if you think that's the right thing to do. – NickD Jun 17 '22 at 18:26
  • Given the context I see no harm in the answer or it's wording. I need reminders of these things myself. – ocodo Jun 18 '22 at 01:09