In some cases you can use either function to add an element to a list. That you can do that does not mean that you should, however.
The recommendation by Emacs is to use only add-hook
for a hook. And pushnew
(cl-pushnew
) is generally recommended in place of add-to-list
. (Common Lisp does not even have something like add-to-list
.)
Note that, unlike add-to-list
, pushnew
does not require its second argument to evaluate to a symbol (variable) -- it is a very general macro. But it is a macro, not a function, so you cannot map it (e.g. cl-mapcar
), funcall
it, etc.
add-to-list
can typically be replaced by macro pushnew
. The first add-to-list
arg is a symbol that is used as a list-valued variable. Its second is any Lisp value. Its fourth, COMPARE-FN
is a function that tests whether the element to add is already present - it has no counterpart in add-hook
, which always tests using equal
.
The first add-hook
arg, the hook variable, need not have a list as its value -- it can be a single function. The second arg should be a function, but there is no check that it is. (That answers your second question.) And its fourth arg, LOCAL
, means update the buffer-local, not the global, value of the hook - it has no counterpart in add-to-list
.
What you mention about their difference, that add-hook
binds an unbound symbol, is true. That's important for a hook, in particular, because most hook variables are not created by default. They are implicit in the definition of a mode, and they are created on the fly only when they are actually needed.
Is that bind-if-not-bound behavior what you really want for every add-something-to-a-list use case? I'm guessing probably not. But if that's important to you for some reason then you can easily add such behavior to your own function that adds an element to a variable that should be list-valued.
See C-h f
for other differences, or (better) check their definitions in subr.el
.
If you understand the differences then you can of course use each any way you like, taking its behavior into account. But for readability by others (or by you, later on), even in contexts where the behavior differences might not matter, it generally makes sense to use them as they were intended.
By using them in the intended/expected way, you do not mislead readers of your code. The principal reason for using each as it is intended is to signal the intention/use to others and to yourself later.
I differ from SDS's fine answer in this respect:
add-to-list
is not just for "other global customization variables". It has nothing particularly to do with customization variables or with .emacs
.
It is not the case that add-hook
and add-to-list
are only for your .emacs
and that pushnew
is only for Lisp code. For one thing, .emacs
contains Lisp code. ;-)
It is perfectly fine, and common, for Lisp code to use add-hook
and add-to-list
(though pushnew
is more common than add-to-list
nowadays). (For decades Emacs did not even have pushnew
; add-to-list
was then recommended for all non-hook lists.)
And it is perfectly fine for your .emacs
file to use pushnew
.
The simple rule to remember is just this:
Use add-hook
only with hook variables, and add-to-list
or pushnew
only to add an element to a (non-hook) list value.
If you really need or want something different, it is pretty easy to define it, and a good place to start is to look at the existing code for add-hook
and either add-to-list
or pushnew
.