linuxterminalclojureboot-clj

java.lang.IllegalArgumentException error depending on symbol names used - Clojure


I am a beginner at Clojure. I am performing one operation twice, but with changed symbols lang against language

One case it is working well, another is throwing an error: java.lang.IllegalArgumentException: No method in multimethod 'my-method' for dispatch value: null

I am not sure if it is caused by an Clojure syntax or there is something wrong in my linux configuration. I have Debian Stretch and boot.clj.

The error happens in the terminal. Here you are the both peaces of code an the error:

s@lokal:~$ boot repl
nREPL server started on port 36091 on host 127.0.0.1 - nrepl://127.0.0.1:36091
java.lang.Exception: No namespace: reply.eval-modes.nrepl found
REPL-y 0.4.1, nREPL 0.4.4
Clojure 1.8.0
OpenJDK 64-Bit Server VM 1.8.0_181-8u181-b13-2~deb9u1-b13
        Exit: Control+D or (exit) or (quit)
    Commands: (user/help)
        Docs: (doc function-name-here)
              (find-doc "part-of-name-here")
Find by Name: (find-name "part-of-name-here")
      Source: (source function-name-here)
     Javadoc: (javadoc java-object-or-class-here)
    Examples from clojuredocs.org: [clojuredocs or cdoc]
              (user/clojuredocs name-here)
              (user/clojuredocs "ns-here" "name-here")
boot.user=> (do
       #_=> (defmulti my-method (fn[x] (x "lang")))
       #_=> (defmethod my-method "English" [params] "Hello!")
       #_=> (def english-map {"id" "1", "lang" "English"})
       #_=>     (my-method english-map)
       #_=> )
"Hello!"
boot.user=> 

boot.user=> (do
       #_=> (defmulti my-method (fn[x] (x "language")))
       #_=> (defmethod my-method "English" [params] "Hello!")
       #_=> (def english-map {"id" "1", "language" "English"})
       #_=>     (my-method english-map)
       #_=> )

java.lang.IllegalArgumentException: No method in multimethod 'my-method' for dispatch value: null
boot.user=>

I must add that before it worked with language but not with lang. It also turned to work or did not when I was changing a my-method symbol name with mymetho-d or greeting.


Solution

  • defmulti defines a var, and subsequent calls to defmulti with the same name do nothing, so your second defmulti call is ineffective and the original dispatch function remains. There's remove-method and remove-all-methods for removing defmethod definitions, but to remove a defmulti definition (without restarting REPL) you can use alter-var-root to set the var to nil:

    (defmulti my-method (fn [x] (x "lang")))
    (defmethod my-method "English" [params] "Hello!")
    (def english-map {"id" "1", "lang" "English"})
    (my-method english-map)
    => "Hello!"
    
    (alter-var-root #'my-method (constantly nil)) ;; set my-method var to nil
    
    (def english-map {"id" "1", "language" "English"})
    (defmulti my-method (fn [x] (x "language")))
    (defmethod my-method "English" [params] "Hello!")
    (my-method english-map)
    => "Hello!"
    

    You can use ns-unmap to similar effect:

    (ns-unmap *ns* 'my-method)