39

I've found that different packages in their installation instructions use either push or add-to-list (For example adding a directory to load-path) and I was wondering what the difference is and what the use case for each would be.

1
  • 4
    I was struggling to convert code using add-to-list to code using cl-pushnew, and I found this blog post to be quite enlightling: yoo2080.wordpress.com/2013/09/11/…
    – Daniel
    Commented Apr 7, 2018 at 12:57

3 Answers 3

29

What #zck mentions is one difference. But if that were the only difference then you could ask about cl-pushnew and add-to-list.

Another important difference: add-to-list is a function, which means that it evaluates all of its arguments, in particular, the first one. push is a macro (as is cl-pushnew) - it does not evaluate its second argument; instead, it interprets it as a generalized place.

For example, if the second argument is a symbol then it is regarded as a variable, and the value of the first argument is consed onto the value of that symbol as a variable, and the variable is set to that new cons.

As the doc string of add-to-list says:

This is handy to add some elements to configuration variables,
but please do not abuse it in Elisp code, where you are usually
better off using `push' or `cl-pushnew'.
8
  • 7
    Also according to the byte-compiler: add-to-list can't use lexical var ...; use push or cl-pushnew
    – Malabarba
    Commented Jan 15, 2015 at 12:05
  • (push (5 6) my-list) still gives me an error -- 5 is not a function. How is this different than add-to-list's behavior? Commented May 19, 2019 at 17:46
  • @markasoftware: What are you trying to do? If you want to push the list (5 6) to the place (value of variable) my-list then you need to create the list (5 6). One way to do that is to use '(5 6); another is to use (list 5 6). push evaluates the argument.
    – Drew
    Commented May 19, 2019 at 19:56
  • @Drew you say now that it evaluates the argument, but your answer literally states "it does not evaluate its first argument", which is the source of my confusion. Commented May 20, 2019 at 2:00
  • @markasoftware: I'm sorry; I had a typo - I wrote "first argument" where I should have written "second argument". Corrected now - thanks. The second arg to push is a place, such as a variable. The first arg is evaluated, consed onto the value of that variable, and the variable is set to that new cons. add-to-list evaluates its first arg to produce the variable whose value gets updated. push does not evaluate its second arg, which is the variable to update. The arg order is reversed between the two.
    – Drew
    Commented May 20, 2019 at 2:46
22

Another difference:

push adds element to the beginning of list.

add-to-list allows you to add element to either the beginning or end of list.

(setq testasdf nil)

(push 'a testasdf)

testasdf
(a)

(add-to-list 'testasdf 'b)

testasdf
(b a)

;; add element to the end
(add-to-list 'testasdf "hello" t)

testasdf
(b a "hello")
18

From the Emacs documentation, or C-h f push:

Macro: push element listname

This macro creates a new list whose car is element and whose cdr is the list specified by listname, and saves that list in listname.

From the same page, or C-h f add-to-list:

Function: add-to-list symbol element &optional append compare-fn

This function sets the variable symbol by consing element onto the old value, if element is not already a member of that value.

So add-to-list only pushes if the element isn't already there.

1
  • cl-pushnew behaves like add-to-list. Commented Mar 5, 2019 at 22:49

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.