Mixed string and keyword dispatch values break pprint pretty-printer
Hi @camsaul appears mixing dispatch values like in the following examples break the default pretty-printer pprint. Typically, this shouldn't be a problem except when you store a multimethod in some compound data you pass around - like state of a finite state machine or something. The moment REPL attempts to pretty print such a value it'll throw an exception. Maybe related to problem with sort you mention in another issue.
Version: methodical/methodical {:mvn/version "1.0.111"}
To reproduce, try any of these:
Examples 1:
(defmulti boom (fn [arg] arg))
(defmethod boom :bar [_] :bar)
(pprint boom)
;; => works fine
(defmethod boom "bar" [_] "bar")
(pprint boom)
;; => with this method added throws
stacktrace
1. Unhandled java.lang.ClassCastException
class clojure.lang.Keyword cannot be cast to class java.lang.String
(clojure.lang.Keyword is in unnamed module of loader 'app';
java.lang.String is in module java.base of loader 'bootstrap')
String.java: 140 java.lang.String/compareTo
Util.java: 153 clojure.lang.Util/compare
APersistentVector.java: 442 clojure.lang.APersistentVector/compareTo
Util.java: 153 clojure.lang.Util/compare
core.clj: 842 clojure.core/compare
core.clj: 833 clojure.core/compare
AFunction.java: 51 clojure.lang.AFunction/compare
TimSort.java: 355 java.util.TimSort/countRunAndMakeAscending
TimSort.java: 220 java.util.TimSort/sort
Arrays.java: 1233 java.util.Arrays/sort
core.clj: 3117 clojure.core/sort
core.clj: 3104 clojure.core/sort
core.clj: 3104 clojure.core/sort
standard.clj: 20 methodical.impl.method-table.standard/dispatch-value-map
standard.clj: 15 methodical.impl.method-table.standard/dispatch-value-map
standard.clj: 34 methodical.impl.method-table.standard.StandardMethodTable/pretty
core.clj: 41 pretty.core/eval17673/fn
MultiFn.java: 229 clojure.lang.MultiFn/invoke
pprint_base.clj: 194 clojure.pprint/write-out
dispatch.clj: 79 clojure.pprint/pprint-simple-list/fn
dispatch.clj: 78 clojure.pprint/pprint-simple-list
dispatch.clj: 88 clojure.pprint/pprint-list
dispatch.clj: 87 clojure.pprint/pprint-list
MultiFn.java: 229 clojure.lang.MultiFn/invoke
pprint_base.clj: 194 clojure.pprint/write-out
pprint_base.clj: 171 clojure.pprint/write-out
core.clj: 41 pretty.core/eval17673/fn
MultiFn.java: 229 clojure.lang.MultiFn/invoke
pprint_base.clj: 194 clojure.pprint/write-out
dispatch.clj: 79 clojure.pprint/pprint-simple-list/fn
dispatch.clj: 78 clojure.pprint/pprint-simple-list
dispatch.clj: 88 clojure.pprint/pprint-list
dispatch.clj: 87 clojure.pprint/pprint-list
MultiFn.java: 229 clojure.lang.MultiFn/invoke
pprint_base.clj: 194 clojure.pprint/write-out
pprint_base.clj: 171 clojure.pprint/write-out
core.clj: 41 pretty.core/eval17673/fn
MultiFn.java: 229 clojure.lang.MultiFn/invoke
pprint_base.clj: 194 clojure.pprint/write-out
dispatch.clj: 79 clojure.pprint/pprint-simple-list/fn
dispatch.clj: 78 clojure.pprint/pprint-simple-list
dispatch.clj: 88 clojure.pprint/pprint-list
dispatch.clj: 87 clojure.pprint/pprint-list
MultiFn.java: 229 clojure.lang.MultiFn/invoke
pprint_base.clj: 194 clojure.pprint/write-out
pprint_base.clj: 171 clojure.pprint/write-out
core.clj: 41 pretty.core/eval17673/fn
MultiFn.java: 229 clojure.lang.MultiFn/invoke
pprint_base.clj: 194 clojure.pprint/write-out
pprint_base.clj: 249 clojure.pprint/pprint/fn
pprint_base.clj: 248 clojure.pprint/pprint
pprint_base.clj: 241 clojure.pprint/pprint
pprint_base.clj: 245 clojure.pprint/pprint
pprint_base.clj: 241 clojure.pprint/pprint
Example 2
(defmulti bam (fn [arg] arg))
(defmethod bam [:bar] [_] :bar)
(pprint bam)
;; => works fine
(defmethod bam ["bar"] [_] "bar")
(pprint bam)
;; => with this method added throws
Example 3
(defmulti foo first)
(defmethod foo "bar" [_] 42)
(defmethod foo ["bar"] [_] 42)
(pprint foo)
(defmulti baz first)
(defmethod baz :bar [_] 42)
(defmethod baz [:bar] [_] 42)
(pprint baz)
Def sort related: throws attempting to sort primaries so, yeah, likely related to https://github.com/camsaul/methodical/issues/140
For now and as a temp hack I dropped sort and altered var root:
(defn- dispatch-value-map
"Create a representation of `primary` and `aux` methods using their dispatch values for pretty-printing a method table."
[primary aux]
(not-empty
(merge
(when-let [dvs (not-empty (vec #_removed_sort_here (keys primary)))]
{:primary dvs})
(when-let [aux-methods (not-empty
(into {} (for [[qualifier dv->fns] aux
:let [dvs (for [[dv fns] dv->fns
_f fns]
dv)]
:when (seq dvs)]
[qualifier (vec (sort dvs))])))]
{:aux aux-methods}))))
(alter-var-root
(var methodical.impl.method-table.standard/dispatch-value-map)
(fn [_f]
dispatch-value-map))
ugly but does the trick.
Hi @vkz, would you be interested in submitting a PR for this?