duct

2019-02-06T16:09:27.140800Z

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

2019-02-06T17:58:20.141800Z

@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 🙂

2019-02-06T17:58:50.142100Z

cool

2019-02-06T17:59:30.142900Z

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

2019-02-06T18:00:43.144900Z

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

2019-02-06T18:01:17.145900Z

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

2019-02-06T18:01:19.146Z

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

2019-02-06T18:01:23.146200Z

yeah

2019-02-06T18:02:19.147400Z

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.

2019-02-06T18:02:38.148100Z

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

2019-02-06T18:02:39.148200Z

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

2019-02-06T18:03:36.149Z

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

2019-02-06T18:03:38.149100Z

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

2019-02-06T18:03:40.149300Z

yeah

2019-02-06T18:03:58.149500Z

that was the ClassCastException

2019-02-06T18:04:04.149700Z

not got a repl open just now

2019-02-06T18:04:36.150300Z

was meaning to isolate the causes in a minimal harness

2019-02-06T18:05:56.151500Z

ahh right enough there’s a :tag hint

2019-02-06T18:06:18.151900Z

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

2019-02-06T18:06:33.152400Z

Since they're all public members: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/MultiFn.java

2019-02-06T18:06:52.152900Z

yeah was just thinking something like that would be the solution

2019-02-06T18:06:54.153200Z

thanks

2019-02-06T18:07:10.153600Z

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

2019-02-06T18:07:45.154600Z

really? I avoid mutating anything just now

2019-02-06T18:07:46.154700Z

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

2019-02-06T18:07:52.154900Z

does that already

2019-02-06T18:09:55.155600Z

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

2019-02-06T18:10:36.156400Z

Like:

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

2019-02-06T18:13:07.157400Z

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

2019-02-06T18:13:54.158100Z

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

2019-02-06T18:17:32.159Z

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.

2019-02-06T18:18:41.159900Z

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.

2019-02-06T19:29:46.160300Z

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