ClojureDocs

Nav

Namespaces

conj!

clojure.core

Available since 1.1 (source)
  • (conj!)
  • (conj! coll)
  • (conj! coll x)
Adds x to the transient collection, and return coll. The 'addition'
may happen at different 'places' depending on the concrete type.
2 Examples
;; As seen on http://clojure.org/transients
;; array is initially made transient, modified then
;; finally made persistent.

;; Note: This example correctly always uses the return value of conj! for
;; future modifications, not the original value of v.  See assoc! examples,
;; and another example for conj!, for some discussion of why this is important.

(defn vrange2 [n]
  (loop [i 0 v (transient [])]
    (if (< i n)
      (recur (inc i) (conj! v i))
      (persistent! v))))

user=> (vrange2 10)
[0 1 2 3 4 5 6 7 8 9]
;; The next function below uses conj! incorrectly, ignoring its return
;; value.

user=> (defn into-bad-example-bash-in-place [to-coll from-coll]
         (let [t (transient to-coll)]
           (loop [f (seq from-coll)]
             (if-let [s (seq f)]
               (do
                 (conj! t (first s))
                 (recur (next s)))
               (persistent! t)))))

;; The first example call below returns the desired value.

user=> (into-bad-example-bash-in-place {:a 1, :b 2, :c 3} {:d 4, :e 5})
{:a 1, :b 2, :c 3, :d 4, :e 5}

;; However, it is by accident that it is correct.  This effect can be
;; subtle and surprising to many, because many experiments will return
;; the desired values, as the example above does.

;; The return value is correct for these inputs because all of these
;; calls to conj! not only return the mutated object that we should be
;; using, but they also happen to mutate the object in place that it
;; is passed.  Thus ignoring the return value happens not to lead to
;; incorrect behavior here.

;; However, conj! _can_ in some cases return a different object than
;; the one it was passed, and _not_ mutate the object it is passed.
;; Look at this return value.

user=> (into-bad-example-bash-in-place
           {:a 1, :b 2, :c 3, :d 4, :e 5, :f 6, :g 7, :h 8}
           {:i 9})
{:a 1, :b 2, :c 3, :d 4, :e 5, :f 6, :g 7, :h 8}

;; This result is not what we want, because key :i is not present in
;; the result anywhere.  conj! returned a different object than the
;; one it was given, but the function above does not use the return
;; value, instead discarding it.

;; The function below uses conj! as it should be, always using its
;; return value in future calls on the transient collection.

user=> (defn into-better-use-return-value [to-coll from-coll]
         (loop [t (transient to-coll)
                f (seq from-coll)]
           (if-let [s (seq f)]
             (recur (conj! t (first s))
                    (next s))
             (persistent! t))))

user=> (into-better-use-return-value {:a 1, :b 2, :c 3} {:d 4, :e 5})
{:a 1, :b 2, :c 3, :d 4, :e 5}

user=> (into-better-use-return-value
           {:a 1, :b 2, :c 3, :d 4, :e 5, :f 6, :g 7, :h 8}
           {:i 9})
{:e 5, :g 7, :c 3, :h 8, :b 2, :d 4, :f 6, :i 9, :a 1}

;; The keys are not in the same order, but recall that regular Clojure
;; maps are not sorted in any predictable way, as opposed to
;; sorted-map's.  However, all 9 of the keys that we expect to be
;; there, are there.
See Also

Returns a new, transient version of the collection, in constant time.

Added by gstamp

When applied to a transient map, adds mapping of key(s) to val(s). When applied to a transient vec...

Added by jafingerhut

Returns a transient map that doesn't contain a mapping for key(s).

Added by jafingerhut

conj[oin]. Returns a new collection with the xs 'added'. (conj nil item) returns (item). (co...

Added by mars0i
0 Notes
No notes for conj!