Do Clojure still have rooms to improve at compiler level?

I don’t know about it being simple, but if you want to use destructuring with efficient dispatch you can look at this library: GitHub - joinr/structural: Destructuring plus type hinting for more performant clojure.

2 Likes

On jvm version (probably clj as well):

Function invocation path (map-as-function) is typically lowest overhead. So going with (the-map :some-key) will work fast and be portable. I changed my “idioms” to start using this when I realized that (I used to use keyword-as-function and clojure.core/get quite a bit before). It’s like 5ns faster on my machine than the kw one (if you believe the nanos…). The tradeoff is that you are losing the support of the broader java.util.Map and java.util.List and array support that nth/get basically paper over for you; and non-clojure types aren’t IFns so they will throw an exception. Still, if you’re slamming clojure maps, sets, vectors, then it’s a clean and fast way to get the lower level speed.

Destructuring will still cost, since it assumes maximum polymorphism and doesn’t leverage any type hint information. So sequential things always go through clojure.core/nth, and map-like things always use clojure.core/get, both of which do checks and branching. You get substantially faster if you avoid these things, namely by doing what I mentioned above, or (in some cases like with direct field access) use type hints and direct method/field invocation. The library @didibus mentioned provides some tooling to allow you to leverage types a bit, which is handy with things like records or deftypes or jvm objects that can be really efficiently accessed, or even instances of Indexed or ILookup. Savings can be substantial for hot loops (which was the origin of the lib). I think the clj-fast lib is incorporating its own variant of these ideas. It would ultimately be “nice” to have some optimizing compiler passes akin to what SBCL does, where you can leverage the type system / inference engine to then generate even better code with user-defined safety/debug/speed levels (e.g. if you want to force type specialization akin to what structural does, compiler could just unpack all that stuff for you).

2 Likes

The Clojure compiler is old and pre-dates “AST as data” implemented in ClojureScript. I’m not sure that the claim about Clojure Dart is true since I believe they started with ClojureScript so the “AST as data” is probably true there. ClojureScript and probably Clojure Dart should conform to the same base AST rep defined by tools.analyzer. Given that, I definitely don’t see why transformations could not be shared.

3 Likes

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