Great idea on interning a var at macro-time and then using it later! I did something similar for the ClojureScript implementation of inline caching but for some odd reason didn't think of doing it for the Clojure version. I'm seeing a big performance improvement for the [:a :b :c] benchmark from my post - about 15% faster than before and now very close to full manual precompilation.
Here's the commit: https://github.com/nathanmarz/specter/commit/fbca7ab99c84d93a28f7773f1c56be12e1a939a3 On Tuesday, May 31, 2016 at 9:33:29 PM UTC-4, puzzler wrote: > > I think this is an interesting problem, so here are some additional > brainstorms on the issue that may or may not be useful... > > One strategy to create a global mutable variable from inside the function > would be to use def at macroexpansion time to create a var, and then just > refer to it in the expansion, like this: > > (defmacro expand-to-something-with-mutable-global [] > ; At macroexpansion time, create a (private) var containing a volatile. > (let [global-name (gensym "cache")] > (eval `(def ^:private ~global-name (volatile! nil))) > ; Now macro can refer to this var, can use as a cache, etc. > `(if-let [cache-contents# (deref ~global-name)] > (do-something-with cache-contents#) > (reset! ~global-name init-value-for-cache)))) > > Not sure if this would be any faster than ConcurrentHashMap, but I would > guess that it would be if Clojure resolves the location of the var in > memory once, at compile-time. > > A related technique would be for Specter to maintain an ArrayList of > volatiles. At macroexpansion time, you add a fresh volatile to the end of > the ArrayList, noting the index of its location, and then inside the macro > you hardcode a lookup in the ArrayList at the specific index to retrieve > the volatile containing the cache for this particular expansion. I would > expect this to be faster than looking up in a hash map, although there'd be > some additional concurrency/locking details to worry about that I assume > ConcurrentHashMap handles for you. > > Or just use an ArrayList's slot directly as the cache (rather than storing > a volatile to add a level of indirection), but then the concurrency > logistics would be even more complicated. > > On Tue, May 31, 2016 at 12:50 PM, Nathan Marz <natha...@gmail.com > <javascript:>> wrote: > >> No, because that global mutable variable would need to be specifiable by >> Specter on usage of the library. For example, if you wrote: >> >> (defn foo [] >> (select [:a :b] {:a {:b 1}})) >> >> `select` has no ability to control anything outside the context of its >> form. It certainly can't wrap `foo` to put a volatile field in its closure. >> So for the static-field idea, it would expand to something like: >> >> (defn foo [] >> (static-field [pathcache] >> (if-not pathcache (set! pathcache ...)) >> ... >> )) >> >> >> >> On Tuesday, May 31, 2016 at 3:15:26 PM UTC-4, puzzler wrote: >>> >>> In your writeup, you say that there would be further speed benefits if >>> you could have a global mutable variable within the context of a function >>> (like a static field). >>> >>> Can't you effectively accomplish that already in Clojure like this?: >>> >>> (let [mycache (volatile! nil)] >>> (defn foo [] >>> ...))) >>> >> -- >> You received this message because you are subscribed to the Google >> Groups "Clojure" group. >> To post to this group, send email to clo...@googlegroups.com >> <javascript:> >> Note that posts from new members are moderated - please be patient with >> your first post. >> To unsubscribe from this group, send email to >> clojure+u...@googlegroups.com <javascript:> >> For more options, visit this group at >> http://groups.google.com/group/clojure?hl=en >> --- >> You received this message because you are subscribed to the Google Groups >> "Clojure" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to clojure+u...@googlegroups.com <javascript:>. >> For more options, visit https://groups.google.com/d/optout. >> > > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.