Clojure: cons (seq) vs. conj (list)
clojure, collections, sequence
Solution
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.
Problem
I know that `cons` returns a seq and `conj` returns a collection. I also know that `conj` "adds" the item to the optimal end of the collection, and `cons` always "adds" the item to the front. This example illustrates both of these points: ``` user=> (conj [1 2 3] 4) ; returns a collection [1 2 3 4] user=> (cons 4 [1 2 3]) ; returns a seq (4 1 2 3) ``` For vectors, maps, and sets these differences make sense to me. However, for lists they seem identical. ``` user=> (conj (list 3 2 1) 4) ; returns a list (4 3 2 1) user=> (cons 4 (list 3 2 1)) ; returns a seq (4 3 2 1) ``` Are there any examples using lists where `conj` vs. `cons` exhibit different behaviors, or are they truly interchangeable? Phrased differently, is there an example where a list and a seq cannot be used equivalently?