Fork me on GitHub
#duct
<
2019-02-06
>
rickmoynihan16:02:27

I haven’t created an official release yet — currently trialing it out. Any comments greatfully received.

weavejester17:02:20

@rickmoynihan Looks pretty reasonable, and a good tool for stubbing out multimethods. When you're happy with it, submit it to the Clojure toolbox and I'll add it to the directory 🙂

rickmoynihan17:02:30

my main issue with it, which I still need to investigate more fully is how it interacts with ig/load-namespaces

rickmoynihan18:02:43

I haven’t fully debugged it yet… but it looked very much like if the method bodies aren’t loaded before you with-redef-methods it - then you’d get a classcast exception

weavejester18:02:17

I see what you mean... If a defmethod is hit for an overridden multimethod.

rickmoynihan18:02:19

so I had to resort to loading the namespaces by hand, before redef-ing them. I’m guessing because load-namespaces replaces the var

weavejester18:02:19

I don't think load-namespaces replaces the var... since the var would be integrant.core/init-key, which should already be loaded, because load-namespaces is in integrant.core.

rickmoynihan18:02:38

yeah you’re right — it’s the internals of the defmethod though

weavejester18:02:39

But what it will do is call defmethod on init-key, so it expects init-key to be a multimethod.

weavejester18:02:36

Okay, so defmethod expects a clojure.lang.MultiFn...

rickmoynihan18:02:38

not sure quite what you’re saying… what I’m saying is that the internals of a multi are mutable state too

rickmoynihan18:02:58

that was the ClassCastException

rickmoynihan18:02:04

not got a repl open just now

rickmoynihan18:02:36

was meaning to isolate the causes in a minimal harness

rickmoynihan18:02:56

ahh right enough there’s a :tag hint

weavejester18:02:18

So I think I'd copy the multimethod... like, (clojure.lang.MultiFn. (.name m) (.dispatchFn m) (.defaultDispatchVal m) (.hierarchy m))

rickmoynihan18:02:52

yeah was just thinking something like that would be the solution

weavejester18:02:10

And then override the copied MultiFn by adding your own .addMethod.

rickmoynihan18:02:45

really? I avoid mutating anything just now

weavejester18:02:46

Maybe set up a default dispatch that goes back to the original?

rickmoynihan18:02:52

does that already

weavejester18:02:55

Even though you'd be mutating the MultiFn clone, you'd be throwing away the clone afterwards.

weavejester18:02:36

Like:

(defn clone-multimethod [m]
  (let [m' (clojure.lang.MultiFn. (.name m) ...)]
    (doseq [[k f] (methods m)]
      (.addMethod m' k f))
    m'))

weavejester18:02:07

Or just add a default dispatch going back to the original, maybe:

weavejester18:02:54

(defn clone-multimethod [m]
  (let [m' (clojure.lang.MultiFn. (.name m) ...)]
    (.addMethod m' (.defaultDispatchVal m) m)
    m'))

weavejester18:02:32

Although... I guess you'd want a proxy of the MultiFn, so you could ensure that .addMethod doesn't override the stuff you've overridden yourself.

weavejester18:02:41

Perhaps at that point it's better to go back to Java and inherit a new class from the old... unless proxy does that for us. I can't remember if it keeps inherited methods or not.

rickmoynihan19:02:46

sorry had to rush off out… will have a look and think