One difference is that conj
accepts any number of arguments to insert into a collection, while cons
takes just one:
(conj '(1 2 3) 4 5 6)
; => (6 5 4 1 2 3)
(cons 4 5 6 '(1 2 3))
; => IllegalArgumentException due to wrong arity
Another difference is in the class of the return value:
(class (conj '(1 2 3) 4))
; => clojure.lang.PersistentList
(class (cons 4 '(1 2 3))
; => clojure.lang.Cons
Note that these are not really interchangeable; in particular, clojure.lang.Cons
does not implement clojure.lang.Counted
, so a count
on it is no longer a constant time operation (in this case it would probably reduce to 1 + 3 -- the 1 comes from linear traversal over the first element, the 3 comes from (next (cons 4 '(1 2 3))
being a PersistentList
and thus Counted
).
The intention behind the names is, I believe, that cons
means to cons(truct a seq)1, whereas conj
means to conj(oin an item onto a collection). The seq
being constructed by cons
starts with the element passed as its first argument and has as its next
/ rest
part the thing resulting from the application of seq
to the second argument; as displayed above, the whole thing is of class clojure.lang.Cons
. In contrast, conj
always returns a collection of roughly the same type as the collection passed to it. (Roughly, because a PersistentArrayMap
will be turned into a PersistentHashMap
as soon as it grows beyond 9 entries.)
1 Traditionally, in the Lisp world, cons
cons(tructs a pair), so Clojure departs from the Lisp tradition in having its cons
function construct a seq which doesn't have a traditional cdr
. The generalised usage of cons
to mean "construct a record of some type or other to hold a number of values together" is currently ubiquitous in the study of programming languages and their implementation; that's what's meant when "avoiding consing" is mentioned.