Liking cljdoc? Tell your friends :D

io.github.frenchy64.fully-satisfies.safer

Variants of clojure.core functions that improve thread-safety and general robustness when passed mutating collections.

We agree that 'Robust programs should not mutate arrays or Iterables that have seqs on them.' https://clojure.org/reference/sequences Eductions inhabit a middle ground and might be the most practical application of this namespace. They are designed to be walked from first to last like seqs, but each element is recomputed instead of being cached like persistent seqs. This becomes problematic if a sequence function walks its argument multiple times without first binding a seq.

For example, clojure.core/split-at could disagree on the take/drop parts of the collection if the coll is mutated between realizing the splits. Here, any one call to the eduction alternates between [0 1 2 3 4 5 6 7 8 9] and [9 8 7 6 5 4 3 2 1 0]. However, split-at incorrectly splits the eduction as [[0 1 2 3 4] [4 3 2 1 0]], and safer/split-at returns one of the two correct splits: [[0 1 2 3 4] [5 6 7 8 9]].

(deftest split-at-mutation-test (let [up-down (atom true) ed (eduction (map (fn [i] (when (zero? i) (swap! up-down not)) (if @up-down (- 9 i) i))) (range 10))] (is (= [[0 1 2 3 4] [4 3 2 1 0]] (split-at 5 ed))) (is (= [[0 1 2 3 4] [5 6 7 8 9]] (safer/split-at 5 ed)))))

See io.github.frenchy64.fully-satisfies.safer-test for more details.

The basic trick here is strategically calling seq earlier on the collection argument.

Variants of clojure.core functions that improve thread-safety and general robustness
when passed mutating collections.

We agree that 'Robust programs should not mutate arrays or Iterables that have seqs on them.'
https://clojure.org/reference/sequences
Eductions inhabit a middle ground and might be the most practical application of this namespace.
They are designed to be walked from first to last like seqs, but each element is recomputed
instead of being cached like persistent seqs. This becomes problematic if a sequence function
walks its argument multiple times without first binding a seq.

For example, clojure.core/split-at could disagree on the take/drop parts of
the collection if the coll is mutated between realizing the splits.
Here, any one call to the eduction alternates between [0 1 2 3 4 5 6 7 8 9] and
[9 8 7 6 5 4 3 2 1 0]. However, split-at incorrectly splits the eduction as
[[0 1 2 3 4] [4 3 2 1 0]], and safer/split-at returns one of the two correct splits:
[[0 1 2 3 4] [5 6 7 8 9]].

(deftest split-at-mutation-test
  (let [up-down (atom true)
        ed (eduction (map (fn [i]
                            (when (zero? i)
                              (swap! up-down not))
                            (if @up-down
                              (- 9 i)
                              i)))
                     (range 10))]
    (is (= [[0 1 2 3 4] [4 3 2 1 0]] (split-at 5 ed)))
    (is (= [[0 1 2 3 4] [5 6 7 8 9]] (safer/split-at 5 ed)))))

See io.github.frenchy64.fully-satisfies.safer-test for more details.

The basic trick here is strategically calling seq earlier on the collection argument.
raw docstring

butlastclj

(butlast coll)

Return a seq of all but the last item in coll, in linear time

safer/butlast additionally:

  • is threadsafe for mutable collections, at the cost of an additional call to seq.
  • calls next once per element instead of twice.
Return a seq of all but the last item in coll, in linear time

safer/butlast additionally:
- is threadsafe for mutable collections, at the cost of an additional
  call to seq.
- calls next once per element instead of twice.
sourceraw docstring

drop-lastclj

(drop-last coll)
(drop-last n coll)

Return a lazy sequence of all but the last n (default 1) items in coll

safer/drop-last additionally is thread-safe for mutable collections, at the cost of a call to seq.

Return a lazy sequence of all but the last n (default 1) items in coll

safer/drop-last additionally is thread-safe for mutable collections,
at the cost of a call to seq.
sourceraw docstring

every?clj

(every? pred coll)

Returns true if (pred x) is logical true for every x in coll, else false.

safer/every? additionally is thread-safe for mutable collections.

Returns true if (pred x) is logical true for every x in coll, else
false.

safer/every? additionally is thread-safe for mutable collections.
sourceraw docstring

lastclj

(last coll)

Return the last item in coll, in linear time

safer/last additionally:

  • is thread-safe for mutable collections, at the cost of a call to seq.
  • calls next once every step instead of twice.
Return the last item in coll, in linear time

safer/last additionally:
- is thread-safe for mutable collections, at the cost of a call to seq.
- calls next once every step instead of twice.
sourceraw docstring

not-every?clj

(not-every? pred coll)

Returns false if (pred x) is logical true for every x in coll, else true.

safer/not-every? additionally is thread-safe for mutable collections.

Returns false if (pred x) is logical true for every x in
coll, else true.
      
safer/not-every? additionally is thread-safe for mutable collections.
sourceraw docstring

partitionv-allclj

(partitionv-all n)
(partitionv-all n coll)
(partitionv-all n step coll)

Returns a lazy sequence of vector partitions, but may include partitions with fewer than n items at the end. Returns a stateful transducer when no collection is provided.

safer/partitionv-all additionally is thread-safe for mutable collections and generally robust against a mutating coll.

Returns a lazy sequence of vector partitions, but may include
partitions with fewer than n items at the end.
Returns a stateful transducer when no collection is provided.

safer/partitionv-all additionally is thread-safe for mutable collections
and generally robust against a mutating coll.
sourceraw docstring

sortclj

(sort coll)
(sort comp coll)

Returns a sorted sequence of the items in coll. If no comparator is supplied, uses compare. comparator must implement java.util.Comparator. Guaranteed to be stable: equal elements will not be reordered. If coll is a Java array, it will be modified. To avoid this, sort a copy of the array.

safer/sort additionally is thread-safe for mutable collections (avoids NPE).

Returns a sorted sequence of the items in coll. If no comparator is
supplied, uses compare.  comparator must implement
java.util.Comparator.  Guaranteed to be stable: equal elements will
not be reordered.  If coll is a Java array, it will be modified.  To
avoid this, sort a copy of the array.

safer/sort additionally is thread-safe for mutable collections (avoids NPE).
sourceraw docstring

sort-byclj

(sort-by keyfn coll)
(sort-by keyfn comp coll)

Returns a sorted sequence of the items in coll, where the sort order is determined by comparing (keyfn item). If no comparator is supplied, uses compare. comparator must implement java.util.Comparator. Guaranteed to be stable: equal elements will not be reordered. If coll is a Java array, it will be modified. To avoid this, sort a copy of the array.

safer/sort-by additionally is thread-safe for mutable collections (avoids NPE).

Returns a sorted sequence of the items in coll, where the sort
order is determined by comparing (keyfn item).  If no comparator is
supplied, uses compare.  comparator must implement
java.util.Comparator.  Guaranteed to be stable: equal elements will
not be reordered.  If coll is a Java array, it will be modified.  To
avoid this, sort a copy of the array.

safer/sort-by additionally is thread-safe for mutable collections (avoids NPE).
sourceraw docstring

split-atclj

(split-at n coll)

Returns a vector of [(take n coll) (drop n coll)]

safer/split-at additionally is thread-safe for mutable collections and generally robust against a mutating coll at the cost of a call to seq.

Returns a vector of [(take n coll) (drop n coll)]

safer/split-at additionally is thread-safe for mutable collections
and generally robust against a mutating coll at the cost of a call to seq.
sourceraw docstring

split-withclj

(split-with pred coll)

Returns a vector of [(take-while pred coll) (drop-while pred coll)]

safer/split-with additionally is thread-safe for mutable collections, and generally robust against a mutating coll at the cost of a call to seq.

Returns a vector of [(take-while pred coll) (drop-while pred coll)]

safer/split-with additionally is thread-safe for mutable collections,
and generally robust against a mutating coll at the cost of a call to seq.
sourceraw docstring

splitv-atclj

(splitv-at n coll)

Returns a vector of [(into [] (take n) coll) (drop n coll)]

safer/splitv-at additionally is thread-safe for mutable collections and generally robust against a mutating coll.

Returns a vector of [(into [] (take n) coll) (drop n coll)]

safer/splitv-at additionally is thread-safe for mutable collections
and generally robust against a mutating coll.
sourceraw docstring

take-lastclj

(take-last n coll)

Returns a seq of the last n items in coll. Depending on the type of coll may be no better than linear time. For vectors, see also subvec.

safer/drop-last additionally is thread-safe for mutable collections.

Returns a seq of the last n items in coll.  Depending on the type
of coll may be no better than linear time.  For vectors, see also subvec.

safer/drop-last additionally is thread-safe for mutable collections.
sourceraw docstring

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close