Fork me on GitHub

I was trying out tools.trace for the first time in a long time (latest version 0.7.9), which I believe works by replacing the value of vars whose values are functions, with wrapped functions that also print extra tracing messages.


When you try to use it to trace defprotocol methods, it seems to work as desired when those methods were associated with a type via extend-type, but not if those methods were given in a defrecord or deftype form. I haven't digested the implementation of defprotocol methods yet, but was looking for some hints about how this happens. It seems like when you use extend-type, the Var with the same name as the protocol method name has a value that is a function, and tools.trace can alter this. But for some reason this altering has no effect on the behavior of protocol method calls 'defined with' the type.


This is with Clojure 1.9.0 and latest tools.trace 0.7.9, in case it makes a difference.


I have demo code for various cases, and a (comment ...) section with lots of forms I evaluated in a REPL and comments showing whether I got trace messages or not, in this file:


that's not surprising given my mental model of defprotocol


I'm happy to have your mental model become mine 🙂


well a protocol has an associated interface


and the Fast way to satisfy a protocol is to implement the interface; but that's only physically possible if you can affect the definition of the type


I didn't say, but all of this testing is on Clojure/Java, so OK there is a Java interface created when a protocol is. good.


at the call site for a protocol function, I think there's a check if the object implements the interface, in which case it becomes a basic interface method call


So "the call site for a protocol function" somehow goes through a Clojure Var in some cases, but not others? That is the part where it is muddy for me.


if the object implements the interface, it bypasses the var and just calls the interface method directly


so tools.trace has no opportunity to intercept


The Clojure code that does the call isn't Java interop, it is (proto-method-name object), where there is a Var named proto-method-name.


I'm trying to figure out how changing the value of Var #'proto-method-name fails to affect the behavior of (proto-method-name object) in some cases, but does affect it in others. Maybe I need to go look at the implementation for protocols more.


yes, but it compiles to the thing I described


I think the compiler, when compiling (proto-method-name object), notices (at compile time) that it's a protocol function, and so emits the fancier bytecode


ok, if it is doing that, then I can understand the difference.


I should probably test with something like (apply proto-method-name object) to see if that makes a difference.


I predict it would


thanks for the help


And your predictions are correct! Next I'd like to talk about the price of Tesla stock next week...


well, I'm happy to help you with that using my mental model of defprotocol


Hmmm. So maybe at the call site, it is a Java method call, and the Var is a kind of 'default implementation' that is only used if the object doesn't implement that method?


Because it seems also to avoid going through the Var even if the type of the object is not known at compile time.


yeah it has some kind of fancy runtime class cache


my guess is it's effectively (memoize #(instance? TheInterface %))


maybe without the memory leak features


I'd be curious to know if anyone knows of some library/tool like tools.trace, but that can also print trace messages for such calls. Maybe that would require some kind of JVM-level debugger?


either that or something that fancily recompiles the relevant types


which sounds pretty messy

Alex Miller (Clojure team)22:09:17

You can probably do such things with a Java agent

Alex Miller (Clojure team)22:09:20

You can hot swap classes

😮 4
Alex Miller (Clojure team)22:09:16

Really if you look for a Java thing to do this, it should work for protocols implemented in records/types


but then probably would be less helpful for everything tools.trace is doing correctly