0

I need to build a function that, among other things, modifies, using add-to-list, a list that is passed as an argument to the function itself. I understand that the list passed as an argument is interpreted as a copy of the original list, but how do I modify the original list within the function? Is it possible?

The problem is that such a function isn't designed to return the list value, but rather the modification of that variable should persist even outside the function itself.

Why this code works:

(defun my-working-test ()
  (interactive)
  (let ((MYLIST '()))
    (add-to-list 'MYLIST "foo" t)
    (add-to-list 'MYLIST "bar" t)
    (message "%S" MYLIST)))
;; returns: ("foo" "bar") 

while this other one don't?:

(defun my-add-string-to-list (LIST STRING)
  (add-to-list 'LIST STRING t)
  (buffer-string)) ;; just to show that the function does not returns LIST

(defun my-failing-test ()
  (interactive)
  (let ((MYLIST '()))
    (my-add-string-to-list MYLIST "foo")
    (my-add-string-to-list MYLIST "bar")
    (message (format "%s" MYLIST))))
;; returns: nil

I can't figure out how or whether to quote the MYLIST variable.

Edit. I edited my-add-string-to-list just to suggest that it doesn't return the LIST value.

2

2 Answers 2

1

You can do it with a function - you don't need a macro:

#+begin_src elisp
  (defun my-add-string-to-list (LIST-VAR STRING)
    (add-to-list LIST-VAR STRING t)
    (buffer-string)) ;; just to show that the function does not returns LIST

  (defun my-failing-test ()
    (interactive)
    (let ((MYLIST '()))
      (my-add-string-to-list 'MYLIST "foo")
      (my-add-string-to-list 'MYLIST "bar")
      (message (format "%S" MYLIST))))

  (my-failing-test)
#+end_src

#+RESULTS:
: (foo bar)

You just need to pass the unevaluated symbol down to my-add-string-to-list (and from there to add-to-list).

7
  • I tried but I get: my-add-string-to-list: Symbol’s value as variable is void: MYLIST.
    – Gabriele
    Commented Apr 19 at 19:03
  • Make sure that you copied the code correctly (BTW, I changed the format to "%S" which will improve the output a bit), then put just the code in a file /tmp/foo.el and then say emacs -Q /tmp/foo.el - I get ("foo" "bar") as the result.
    – NickD
    Commented Apr 19 at 20:55
  • This is strange to me: If I evaluate the functions with eval-defun (I tried inverting the order of evaluation) the code doesn't work. If I do evaluate-buffer the code works. It never happened to me.
    – Gabriele
    Commented Apr 19 at 23:09
  • There is something wrong in your setup. Try starting with emacs -Q, then open /tmp/foo.el, evaluate the two defuns in whatever order you want and then evaluate the my-failing-test call. Both orders work the same and they both work.
    – NickD
    Commented Apr 20 at 2:48
  • I found it happens in the *scratch* buffer. If I start Emacs without the -Q option and I open the /tmp/foo.el file, all is ok. If i switch to the scratch buffer and I evaluate again the same functions I get again the same error. Should I open another issue to clarify this point?
    – Gabriele
    Commented Apr 20 at 18:50
0

I solved using defmacro:

(defmacro my-add-string-to-list (LIST STRING)
  `(progn
     (add-to-list ,LIST ,STRING t)
     (buffer-string)))

(defun my-failing-test ()
  (interactive)
  (let ((MYLIST '()))
    (my-add-string-to-list 'MYLIST "foo")
    (my-add-string-to-list 'MYLIST "bar")
    (message (format "%S" MYLIST))))

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.