methodical icon indicating copy to clipboard operation
methodical copied to clipboard

Mixed string and keyword dispatch values break pprint pretty-printer

Open vkz opened this issue 1 year ago • 2 comments

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)

vkz avatar Aug 21 '24 14:08 vkz

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.

vkz avatar Aug 21 '24 14:08 vkz

Hi @vkz, would you be interested in submitting a PR for this?

camsaul avatar Aug 30 '24 18:08 camsaul