This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-09-08
Channels
- # 100-days-of-code (1)
- # announcements (7)
- # beginners (63)
- # cljs-dev (39)
- # clojure (78)
- # clojure-dev (40)
- # clojure-italy (4)
- # clojure-nl (22)
- # clojure-russia (5)
- # clojure-spec (5)
- # clojurescript (60)
- # cursive (8)
- # datomic (6)
- # emacs (1)
- # figwheel-main (53)
- # fulcro (19)
- # jobs-discuss (11)
- # mount (1)
- # off-topic (3)
- # om (1)
- # pedestal (9)
- # philosophy (1)
- # re-frame (19)
- # reagent (4)
- # reitit (5)
- # shadow-cljs (66)
- # tools-deps (64)
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: https://github.com/jafingerhut/demo-docs-tools.trace/blob/master/src/demo1/ns1.clj
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
You can probably do such things with a Java agent
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
I have some code to monkey-patch java method. https://github.com/TristeFigure/shuriken/blob/master/src/shuriken/monkey_patch.clj