There are other implementation details to deal with (as of Clojure 1.10.3), and I would be prepared to update your implementation as Clojure changes (ie., everything I mention below relies on completely undocumented implementation details relevant to Clojure 1.8-1.11):
1. As mentioned by hiredman, protocol methods are reset by
extend. Here is the related issue. If you want your protocol monkey patch to survive an
extend, you need to alter the
:method-builders value for that protocol. However, there are subtle requirements for propagating
.__methodImplCache to the actual implementation. From a glance, I don't think your code handles this correctly (the inner cache is never updated).
2. Protocol methods are inlined in some cases (end users only really notice this when you see a
No single method ... error when you mess up a protocol call). This means your call
(pfoo x) becomes
(.pfoo x) and your monkey patch is circumvented. Try adding
:inline metadata to the protocol method to avoid this:
(-> #'pfoo alter-meta assoc :inline (fn [& args] `((do pfoo) ~@args))
Note that the inlining must be enforced before the Compiler sees any invocations--once it's inlined, it's too late.
I may release a library to help library authors do this kind of thing.