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.
-
3I was struggling to convert code using `add-to-list` to code using `cl-pushnew`, and I found this blog post to be quite enlightling: https://yoo2080.wordpress.com/2013/09/11/emacs-lisp-lexical-binding-gotchas-and-related-best-practices/ – Daniel Apr 07 '18 at 12:57
3 Answers
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'.

- 75,699
- 9
- 109
- 225
-
7Also according to the byte-compiler: `add-to-list can't use lexical var ...; use push or cl-pushnew` – Malabarba Jan 15 '15 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? – markasoftware May 19 '19 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 May 19 '19 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. – markasoftware May 20 '19 at 02: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 May 20 '19 at 02:46
-
@Drew Got it! For my own reference, are there any "places" that `push` accepts but, when quoted, wouldn't work in `add-to-list`? – markasoftware May 20 '19 at 03:31
-
@markasoftware: Not sure what you mean, but `push` accepts a *generalized variable* (the "place"). `add-to-list` accepts only an ordinary variable (a symbol - the result of evaluating its first arg). See the Elisp manual, node [Generalized Variables](https://www.gnu.org/software/emacs/manual/html_node/elisp/Generalized-Variables.html). – Drew May 20 '19 at 16:32
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")

- 1,793
- 12
- 15
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.

- 8,984
- 2
- 31
- 65