Update-proxy is not thread-safe. I took a look at the guts of it and: (. cv (visitField (+ (. Opcodes ACC_PRIVATE) (. Opcodes ACC_VOLATILE)) fmap (. imap-type (getDescriptor)) nil nil))
i.e. there's a private volatile mutable field rather than atom holding the function map. So if (update-proxy foo {"meth1" fn1}) and (update-proxy foo {"meth2" fn2}) were to execute at the same time, it's possible for only one of meth1 and meth2 to end up updated, versus if it used an atom and (swap! fmap merge update-map). Also, I'm no bytecode expert, but this: (. gen (getField ctype fmap imap-type)) (.checkCast gen (totype clojure.lang.IPersistentCollection)) (. gen (loadArgs)) (. gen (invokeInterface (totype clojure.lang.IPersistentCollection) (. Method (getMethod "clojure.lang.IPersistentCollection cons(Object)")))) (. gen (checkCast imap-type)) (. gen (putField ctype fmap imap-type)) looks a lot like it's generating __clojureFnMap = (IPersistentMap)((IPersistentCollection)__clojureFnMap).cons(updateMap); to me, when it surely ought to be merging the maps instead, unless there's something tricky going on here. Which I assume there is, since if it were actually consing one of the maps onto the other and trying to cast the result to IPersistentMap update-proxy would blow up with a CCE at runtime, and instead it works perfectly (modulo the apparent race condition). (And what's with the mixed (. foo (meth & args)) and (.meth foo & args) styles here? Bootstrap's obviously progressed sufficiently at that point for the latter, preferred form to work...) There's also a documented thread-unsafety with proxy-super. At a guess, it looks like proxy-super toggles the proxy into a state where the proxy method calls super instead of calling its proxy function, calls it, and toggles it back. I can easily envision a thread-safer implementation making name-mangled copies of every inherited concrete method for calling super; for the method meth1, generate the equivalent of this Java: public Type1 meth1 (Type2 arg1, Type3 arg2 ...) { __clojureFnBindings.get("meth1").invoke(arg1, arg2 ...); } public Type1 meth1_super_caller (Type2 arg1, Type3 arg2 ...) { super.meth1(arg1, arg2 ...); } only with the first method's body wrapped in something analogous to Clojure: (binding [*proxy-super* meth1_super_caller] ...) and have proxy-super call (apply *proxy-super* args). -- Protege: What is this seething mass of parentheses?! Master: Your father's Lisp REPL. This is the language of a true hacker. Not as clumsy or random as C++; a language for a more civilized age. -- 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