Share your thoughts in the 2021 Clojure Community Survey!

Welcome! Please see the About page for a little more info on how this works.

+2 votes
in Transducers by

A quote from

A transducing process must encapsulate references to the function
returned by invoking a transducer - these may be stateful and unsafe
for use across threads.

  1. Does it mean that it is OK to create unsafe transducers for better
  2. Can core's stateful transducers be written unsafe
    for having performance close to loop/recur?

Benchmarks for unsafe implementation of clojure.core/drop:

(definterface IMutable
  (get [])
  (set [new-val]))

(deftype UnsynchronizedMutable [^:unsynchronized-mutable n]
  (get [_] n)
  (set [_, nv] (set! n nv)))

(defn drop!
   (fn [rf]
     (let [nv (UnsynchronizedMutable. n)]
         ([] (rf))
         ([result] (rf result))
         ([result input]
          (let [^long n (.get nv)]
            (.set nv (dec n))
            (if (pos? n)
              (rf result input)))))))))

    (transduce (comp
                 (map inc)
                 (drop 1))
      + (range 1000)))
  #_"Execution time mean : 39,455570 µs"
    (transduce (comp
                 (map inc)
                 (drop! 1))
      + (range 1000)))
  #_"Execution time mean : 24,979885 µs")

2 Answers

0 votes
selected by
Best answer

The answer can be found in this discussion

So yes, we can use unsafe transducers when we are sure about single-threaded reducing context. But not in general case.

+2 votes

If you're willing to fight this battle, you might be interested by this thread

It's a shame that your IMO solid post was not addressed.
i second that.
I am interested in the details of the JMM, too, but they are fairly subtle, and at least in this case, the Clojure dev team, if they are erring, seem to be erring on the side of maybe sometimes extra safety at the cost of some performance, which seems to be a far preferable choice than erring in the opposite direction.