4 ms·
I think the author's referring to the multiple implementations of persistent maps (i.e. APersistentMap). Clojure's generated docs[1] say there are four implemen
by lgessler 4y ago
I think the author's referring to the multiple implementations of persistent maps (i.e. APersistentMap). Clojure's generated docs[1] say there are four implementations (PersistentArrayMap, PersistentHashMap, PersistentStructMap, PersistentTreeMap), and this Stack Overflow answer[2] explains that the latter two are rarely used, and the former two make up the bulk of actual APersistentMap instances, with the language's core functions for persistent maps changing implementation used under the hood as it likes in order to do what it thinks is best for performance (basically, using PersistentArrayMap if the number of keys is small, and using PersistentHashMap otherwise). You can see this, for example, in PersistentArrayMap's implementation of assoc[3], which replaces itself with a PersistentHashMap if the number of keys has grown over the hardcoded threshold of 16.
So like you say, your experience as an "end user" makes it seem like it's just one data structure at least in interface, though in implementation it's actually doing some performance optimization stuff which, I think I'm willing to grudgingly grant to the author, does make performance harder to reason about in principle. Though in my (very unserious) experience, I think I've enjoyed languages that take a possibly incomplete stab at getting performance right over ones that draw a line leaving it entirely out of scope and declare victory.
I'll equivocate a little and share that I have been bitten by these internals before, though the fault was mine: one time, I was unwittingly relying on an implementation detail of PersistentArrayMaps, which is that they preserve insertion order. PersistentHashMaps don't, and my code was mysteriously breaking when number of keys grew beyond 16 until several hours later I learned much of what I've just shared above.
[1]: https://www.javadoc.io/static/org.clojure/clojure/1.10.1/clojure/lang/APersistentMap.html https://www.javadoc.io/static/org.clojure/clojure/1.10.1/clo...
[2]: https://stackoverflow.com/questions/16516176/what-is-the-difference-between-clojures-apersistentmap-implementations https://stackoverflow.com/questions/16516176/what-is-the-dif...
[3]: https://github.com/clojure/clojure/blob/5ffe3833508495ca7c635d47ad7a1c8b820eab76/src/jvm/clojure/lang/PersistentArrayMap.java#L259L260 https://github.com/clojure/clojure/blob/5ffe3833508495ca7c63...
- eru 4y agoCPython also switches out what internal implementation it uses to represent your dicts based on a few heuristics.
- chii 4y ago> does make performance harder to reason about in principle. the thing is, you don't reason about performance. you measure it. Once you've obtained measurements, you can make decisions based on the outcome of said measurements. If the Runtime (and not just talking about clojure here) makes a decision on performance, and it's suboptimal, your measurements _should_ reveal it - for example, by increasing your input size, the performance graph should show a clear inflexion of where this happens. The real question is whether you _can_ force the Runtime to do something at the programmer's behest, rather than a hidden decision that you cannot control or change. I believe in clojure, you can change the backing data structure, but i'm not sure if you could do it after the fact?
- rawoke083600 4y ago>the thing is, you don't reason about performance. you measure it. You that "fun person" at parties right ? :)
- CrazyPyroLinux 4y agoThe scientific approach would be to invite him to a party and measure it. :)
- germandiago 4y ago> the thing is, you don't reason about performance. you measure it. This is only half-true. You do reason about it and later profile. For example, I want to know if my assinment operator in C++ will run in constant time.