I am missing an important point about defmulti and defmethod. I’ve read several books’ explanation of defmulti, and I’m still confused.
I want to get a random value depending on whether or not it’s a transaction or an amount like 100.00
I want to call (random-val) and either get back an avail-trans value or random decimal amount. I have experimented with putting the functions in a map, but I get the same value back for avail-trans, a \B.
(def^:dynamic map-val {:trans (random-trans) :amt (random-amount)})
Here is the smallest amount of code to show what I’m doing that is not working. I’d appreciate any pointers or help.
(def^:dynamic avail-trans [\B \W \D \A])
(defn random-trans
[]
(nth avail-trans (.nextInt random (count avail-trans))))
(defn random-amount
[]
(float (/ (.nextInt random (count (range 1 10000))) 25 )))
The following is not constructed correctly, but I’m not sure why or how to fix the problem:
(defmulti random-val :val-type)
(defmethod random-val :trans []
(random-trans))
(defmethod random-val :amt []
(random-amount))
Calling (random-val :trans) results in this error:
java.lang.IllegalArgumentException: No method in multimethod ‘random-val’ for dispatch value: null (NO_SOURCE_FILE:0)
A multimethod is created with
defmulti; you’re doing that right.defmultineeds a name and a dispatch function (and a docstring, plus some options, if you desire, but forget about those).When you implement the multimethod with
defmethod, you need to specify the name of the multimethod you’re implementing, the dispatch value it should match, and then the function tail (arglist plus whatever you want it to do).You’re getting
java.lang.IllegalArgumentException: No method in multimethod 'random-val' for dispatch value: null (NO_SOURCE_FILE:0)because when the dispatch function you assignedrandom-val,:val-typeis applied to any other keyword, it gives younull. When Clojure tries to look up a method to match that dispatch value, it fails.But even if it didn’t fail there, your defined methods have 0 arity (take no values), so you need to fix that, too (done above).
Finally, this doesn’t seem like a good use for protocols. Just use your two separate function,
random-amountandrandom-trans.Note, too, that Clojure’s website has a good explanations of multimethods.