# Transients in clojurescript

**URL:** https://clojureverse.org/t/transients-in-clojurescript/9102
**Category:** General Questions
**Tags:** clojurescript
**Created:** [July 10, 2022, 8:11pm UTC](https://clojureverse.org/t/transients-in-clojurescript/9102 "2022-07-10T20:11:02Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![DrLjotsson](https://clojureverse.org/user_avatar/clojureverse.org/drljotsson/32/2602_2.png) [@DrLjotsson](https://clojureverse.org/u/DrLjotsson)
#### Post date: [July 10, 2022, 8:11pm UTC](https://clojureverse.org/t/transients-in-clojurescript/9102/1 "2022-07-10T20:11:02Z")

</div>

Clojure’s transients and their conj!, assoc! functions also exist in Clojurescript. A requirement for using transients in Clojure is thread isolation [Clojure - Transient Data Structures](https://clojure.org/reference/transients).

But JS is not multithreaded - so, my question is: is there a performance benefit from using transients in Clojurescript, and if so, how is that achieved if it is not assuming thread isolation?

---

<div class="post-metadata">

### Author: ![thheller](https://clojureverse.org/user_avatar/clojureverse.org/thheller/32/534_2.png) [@thheller](https://clojureverse.org/u/thheller)
#### Post date: [July 10, 2022, 8:57pm UTC](https://clojureverse.org/t/transients-in-clojurescript/9102/2 "2022-07-10T20:57:41Z")

</div>

Yes, transients gain a similar performance benefit in CLJS as in CLJ.

The isolation part really only means that transients aren’t safe to use anywhere outside the code that is supposed to construct them unless turned `persistent!` first. This is just as true in CLJS as it is in CLJ. It doesn’t actually require threads. Transients mutate in place instead of creating new instances for every operation. This is where they get their performance benefits from, they don’t actually do anything with threads themselves to gain that performance.

Suppose you try

```clojure
(def x (transient {}))
(assoc! x :x 1)
(persistent! x)

```

One might assume to get an empty map as a result of the `(persistent! x)` since `x` started as an empty map and the return value of the `assoc!` was ignored. But you do actually get `{:x 1}` due to the aforementioned “mutate in place”. Also `(assoc x :y 1)` after `persistent!` has been called yields an error.

This is also a mistake people make and maybe unknowingly abusing that fact. `assoc!` must be used just as `assoc`. So, the return value must be used and previous versions discarded. Otherwise weird things will start happening. Threads just add to the ways you can possibly use transients wrong.

---

<div class="post-metadata">

### Author: ![DrLjotsson](https://clojureverse.org/user_avatar/clojureverse.org/drljotsson/32/2602_2.png) [@DrLjotsson](https://clojureverse.org/u/DrLjotsson)
#### Post date: [July 10, 2022, 9:05pm UTC](https://clojureverse.org/t/transients-in-clojurescript/9102/3 "2022-07-10T21:05:14Z")

</div>

Thanks @thheller! Are there any constraints on transients in Clojurescript? Naïvely put, could I use transients in any place that I use their non-transient counterparts?

---

<div class="post-metadata">

### Author: ![DrLjotsson](https://clojureverse.org/user_avatar/clojureverse.org/drljotsson/32/2602_2.png) [@DrLjotsson](https://clojureverse.org/u/DrLjotsson)
#### Post date: [July 10, 2022, 9:14pm UTC](https://clojureverse.org/t/transients-in-clojurescript/9102/4 "2022-07-10T21:14:10Z")

</div>

I think I realized the answer to my second question - I lose immutability, right?

But let’s say that I am reducing over a collection to produce a new collection, like this

```clojure
(persistent!
  (reduce 
    (fn [acc v] (assoc! acc (:id v) v))
    (transient {}) 
    some-coll-of-maps)

```

Would this always lead to a performance benefit if the collection includes, say, over 1000 maps? I guess there is some overhead when calling `persistent!`?

---

<div class="post-metadata">

### Author: ![DrLjotsson](https://clojureverse.org/user_avatar/clojureverse.org/drljotsson/32/2602_2.png) [@DrLjotsson](https://clojureverse.org/u/DrLjotsson)
#### Post date: [July 10, 2022, 9:22pm UTC](https://clojureverse.org/t/transients-in-clojurescript/9102/5 "2022-07-10T21:22:23Z")

</div>

Again, answering my own question. I just checked the source for `group-by`, which is similar to my example function and it actually uses transients [group-by](https://cljs.github.io/api/cljs.core/group-by). So I guess that it is a good idea to use transients in reducers and other places where only the end result needs to be immutable.,

---

<div class="post-metadata">

### Author: ![Phill](https://clojureverse.org/letter_avatar_proxy/v4/letter/p/779978/32.png) [@Phill](https://clojureverse.org/u/Phill)
#### Post date: [July 10, 2022, 10:26pm UTC](https://clojureverse.org/t/transients-in-clojurescript/9102/6 "2022-07-10T22:26:16Z")

</div>

Not quite all such places! Transients do not have all of the retrieval capabilities of persistent collections. Clojure 1.12 is to narrow the gap: [Clojure - Clojure 1.12.0-alpha1](https://clojure.org/news/2022/06/30/clojure1-12-alpha1)

---

<div class="post-metadata">

### Author: ![system](https://clojureverse.org/uploads/default/original/2X/5/51079bf9e4b7d9466242c06cf1e43b9f8bd6da14.png) [@system](https://clojureverse.org/u/system)
#### Post date: [January 9, 2023, 10:27am UTC](https://clojureverse.org/t/transients-in-clojurescript/9102/7 "2023-01-09T10:27:15Z")

</div>

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.
