It looks like defmulti
is caching the dispatch function. Here is a modified version of your code that illustrates the problem:
;; simple fn to resolve defmethod to call, hardcoded to :do-it
(defn who-is-it [person] (:name person))
(spyx (who-is-it {:name :joe}))
(defmulti do-something who-is-it)
(defmethod do-something :homer [person] :doh)
(defmethod do-something :bill [person] :oh-no)
(defmethod do-something :ted [person] :excellent)
(spyx (do-something {:name :homer}))
(spyx (do-something {:name :bill}))
;; now change who-is-it
(defn who-is-it [arg] :ted)
(spyx (who-is-it :wilma)) ;; expected result = :excellent
(spyx (do-something {:name :betty}))
with results:
:reloading (tst.clj.core)
(who-is-it {:name :joe}) => :joe
(do-something {:name :homer}) => :doh
(do-something {:name :bill}) => :oh-no
(who-is-it :wilma) => :ted
:error-while-loading tst.clj.core
Error refreshing environment: java.lang.IllegalArgumentException: No method in multimethod 'do-something' for dispatch value: :betty, compiling:(tst/clj/core.clj:22:27)
It looks like you may need to reinitialize the REPL to redefine the dispatch fn. Even repeating everything did not overwrite do-something
for me:
(defmulti do-something who-is-it)
(defmethod do-something :homer [person] :doh)
(defmethod do-something :bill [person] :oh-no)
(defmethod do-something :ted [person] :excellent)
(spyx (do-something {:name :betty})) ;=> ***same error ***
Error refreshing environment: java.lang.IllegalArgumentException: No method in multimethod 'do-something' for dispatch value: :betty, compiling:(tst/clj/core.clj:30:1)
Here with a new session we see the expected behavior:
;; simple fn to resolve defmethod to call, hardcoded to :do-it
(defn who-is-it [person] (:name person))
(spyx (who-is-it {:name :joe}))
;; now change who-is-it
(defn who-is-it [arg] :ted)
(spyx (who-is-it :wilma)) ;; expected result = :ted
; (spyx (do-something {:name :betty}))
(defmulti do-something who-is-it)
(defmethod do-something :homer [person] :doh)
(defmethod do-something :bill [person] :oh-no)
(defmethod do-something :ted [person] :excellent)
(dotest
(spyx (do-something {:name :betty})))
(do-something {:name :betty}) => :excellent ; *** as expected ***
Update
I tried the ns-unmap
technique Rumid described and it works also. I noticed you have to reissue both the defmulti
and all of the defmethod
statements:
(ns-unmap *ns* 'do-something) ; be sure to remember the quote
(defmulti do-something who-is-it)
(defmethod do-something :homer [person] :doh)
(defmethod do-something :bill [person] :oh-no)
(defmethod do-something :ted [person] :excellent)
(dotest
(newline)
(spyx (do-something {:name :betty}))) ;=> :excellent