Fork me on GitHub
Ben Sless08:09:03

Weeeee, two performance PRs in ring merged 馃帀 Hopefully they'll be able to make it into reitit soon

馃帀 6
delaguardo10:09:55 I remember @U064X3EF3 talked once that devs shouldn鈥檛 use MapEntry directly. I鈥檓 curious - why it is used here? Does it give performance boost in comparison with returning a list of two items for example?

Ben Sless10:09:25

Yes. Faster than both a list and a vector. You wouldn't care about it unless you were doing over 10k qps

Ben Sless10:09:24

It's sometimes hard to know what can and can't be used from the core. I expect MapEntry is used in more than one library out there


I found it - maybe it is already not relevant because it is from 2008.

Ben Sless10:09:54

"I make no promises about the continued existence of MapEntry"


(defrecord Pair [k v])

(defn- split-key-value-pair [^String s]
  (let [i (.indexOf s #=(int \=))]
      (pos? i)  (->Pair (.substring s 0 i) (.substring s (inc i)))
      (zero? i) (->Pair "" (.substring s (inc i)))
      :else     (->Pair s ""))))
I tried to use defrecord and here is my benchmarks:
# MapEntry
Evaluation count : 22697706 in 6 samples of 3782951 calls.
             Execution time mean : 25.380441 ns
    Execution time std-deviation : 6.288547 ns
   Execution time lower quantile : 19.789665 ns ( 2.5%)
   Execution time upper quantile : 32.343785 ns (97.5%)
                   Overhead used : 7.251431 ns

# Pair
Evaluation count : 19948320 in 6 samples of 3324720 calls.
             Execution time mean : 25.188445 ns
    Execution time std-deviation : 3.066662 ns
   Execution time lower quantile : 21.601103 ns ( 2.5%)
   Execution time upper quantile : 28.464897 ns (97.5%)
                   Overhead used : 7.251431 ns

Ben Sless11:09:31

I could define an ad-hoc pair type, compare Pair, MapEntry, [a b] and (list a b)

Ben Sless11:09:35

You also need to compare destructuring perf


Yes, here is how I got the results:

(defn test-1 [^String s]
  (let [kv (split-key-value-pair-map-entry s)]
    [(key kv) (val kv)]))

(defn test-2 [^String s]
  (let [kv (split-key-value-pair-defrecord s)]
    [(:k kv) (:v kv)]))

 (test-1 "foo=42"))

 (test-2 "foo=42"))

Ben Sless12:09:01

Again, I expect no significant difference for map entry and record, you'll see those with list and vector Maybe you'll see a difference with map entry if you direct link

Ben Sless12:09:42

The main difference is that MapEntry exists in Clojure and can be destructured like a user will expect. We don't have tuple or nominal tuple types, MapEntry lets me fake one instead of defining a bespoke one. Maybe it's my bias but I see introducing a new type as having a higher "pass" threshold than introducing a new function.


yeah, fair point


Great that those got in, congrats!

Karol W贸jcik18:09:28

@UK0810AQ2 you are amazing man!

馃槄 2
Ben Sless18:09:57

Thank you all. I'll update a new round of results in stress-server tomorrow morning and will rerun when these get merged. Really curious to see how much can be gained

Ben Sless18:09:49

We will all reap the benefits 馃檪

Ben Sless08:09:02

Which makes me wonder, can reitit be migrated to deps.edn and


sure, malli could also be a multi-module project. I don't have time to migrate, but help most welcome :)

Ben Sless16:09:51

Can't wait to see how much it shaves off the wall


Hi, I am trying to coerce data using the spec-tools, but it seems working not the way as I expected:

(require '[spec-tools.core :as st])

  (s/def ::double double?)
  (s/def ::x (s/keys :req-un [::double]))
  (st/coerce ::x {:double 100} nil)
My expectation that double will become 100.0, but it is not the case atm Are my expectations correct? Or what I am doing wrong? thanks!


@kirill.salykin I would guess having a nil transformer means "do nothing". Also, not sure if JSON/string transformers in spec-tools have mapping from numbers to double, but should be easy to add, also in user side. Pretty sure that malli has those.


So coercion works works from the json/string representation only? No way to coerce clojure into clojure?


you can do any kind of x->edn->x transformations, transformers are both easy to compose and extend. There just isn't a edn->edn transformer pre-packaged, so you have to build one yourself. PR welcome. Here the list of current transformers:


Actually it think strip-* might work for me

Tomas Brejla18:09:31

Hello, I'd like to ask whether the Dev workflow approach described at also applies to reitit.ring/router . Basically I have a reitit ring router with some routes and I want the changes to routes to be refreshed automatically when I save/evaluate the changed definition. Currently I have to issue an integrant system reset which in turn stops and starts new instance of httpkit server with changed routes. This works fine, but I believe shouldn't be necessary. Any hints welcome 馃.