I am implementing a type that is really just a wrapper for hash-maps
(defn as-pairs [m]
(when-not (empty? m)
(seq (persistent! (reduce (fn [s [k vs]]
(reduce (fn [s v] (conj! s [k v])) s vs)) (transient []) m)))))
(deftype Rel [m]
clojure.lang.Seqable
(seq [this] (as-pairs m))
clojure.lang.ILookup
(valAt [this k] (get m k))
(valAt [this k default] (get m k default))
clojure.lang.IPersistentMap
(assoc [this k v] (Rel. (update m k #(conj (or % #{}) v))))
(assocEx [this k v] (throw (Exception.)))
(without [this k] (Rel. (dissoc m k))))
(defn relation [] (Rel. (hash-map)))
It seems to be working as expected
state-machines.maps> (def r (relation))
#'state-machines.maps/r
state-machines.maps> (type r)
state_machines.maps.Rel
state-machines.maps> r
{} ; interesting that it actually displays a map! -- source of problem?
state-machines.maps> (type (assoc r :foo 1 :foo 2 :bar 1))
state_machines.maps.Rel
state-machines.maps> (get (assoc r :foo 1 :foo 2 :bar 1) :foo)
#{1 2}
state-machines.maps> (seq (assoc r :foo 1 :foo 2 :bar 1))
([:foo 1] [:foo 2] [:bar 1])
state-machines.maps> (assoc r :foo 1 :foo 2 :bar 1)
ClassCastException clojure.lang.PersistentVector cannot be cast to java.util.Map$Entry clojure.core/key (core.clj:1518)
state-machines.maps>
looking at the stack trace
1. Unhandled java.lang.ClassCastException
clojure.lang.PersistentVector cannot be cast to java.util.Map$Entry
core.clj: 1518 clojure.core/key
core_print.clj: 212 clojure.core/print-map/fn
core_print.clj: 59 clojure.core/print-sequential
core_print.clj: 208 clojure.core/print-map
core_print.clj: 217 clojure.core/fn
core_print.clj: 217 clojure.core/fn
MultiFn.java: 233 clojure.lang.MultiFn/invoke
pr_values.clj: 35 clojure.tools.nrepl.middleware.pr-values/pr-values/fn/reify
interruptible_eval.clj: 113 clojure.tools.nrepl.middleware.interruptible-eval/evaluate/fn/fn
main.clj: 241 clojure.main/repl/read-eval-print
main.clj: 258 clojure.main/repl/fn
main.clj: 258 clojure.main/repl
main.clj: 174 clojure.main/repl
RestFn.java: 137 clojure.lang.RestFn/applyTo
core.clj: 646 clojure.core/apply
core.clj: 641 clojure.core/apply
regrow.clj: 18 refactor-nrepl.ns.slam.hound.regrow/wrap-clojure-repl/fn
RestFn.java: 1523 clojure.lang.RestFn/invoke
interruptible_eval.clj: 87 clojure.tools.nrepl.middleware.interruptible-eval/evaluate/fn
AFn.java: 152 clojure.lang.AFn/applyToHelper
AFn.java: 144 clojure.lang.AFn/applyTo
core.clj: 646 clojure.core/apply
core.clj: 1881 clojure.core/with-bindings*
core.clj: 1881 clojure.core/with-bindings*
RestFn.java: 425 clojure.lang.RestFn/invoke
interruptible_eval.clj: 85 clojure.tools.nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 55 clojure.tools.nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 222 clojure.tools.nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
interruptible_eval.clj: 190 clojure.tools.nrepl.middleware.interruptible-eval/run-next/fn
AFn.java: 22 clojure.lang.AFn/run
ThreadPoolExecutor.java: 1142 java.util.concurrent.ThreadPoolExecutor/runWorker
ThreadPoolExecutor.java: 617 java.util.concurrent.ThreadPoolExecutor$Worker/run
Thread.java: 745 java.lang.Thread/run
I am assuming that something is happening in one of
core_print.clj: 212 clojure.core/print-map/fn
core_print.clj: 59 clojure.core/print-sequential
core_print.clj: 208 clojure.core/print-map
Is this an interface that I need to implement?
After updating as-pairs
to
(defn as-pairs [m]
(when-not (empty? m)
(seq (persistent! (reduce (fn [s [k vs]]
(reduce (fn [s v] (conj! s (clojure.lang.MapEntry/create k v))) s vs)) (transient []) m)))))
the result is:
state-machines.maps> (assoc (relation) :foo 1 :foo 2 :bar 1)
{:foo 1, :foo 2, :bar 1}
As you suspect, the error is arising in print-map
, which calls seq
on its argument and then calls key
and val
on each element of that sequence. As the error message states, these two functions expect their argument to conform to the java.util.Map$Entry
interface, and Clojure vectors do not conform to that interface.
The solution is to take the [k v]
in your as-pairs
function and replace it with an expression that creates a map entry; see this question for details.