Choosing the right kind of function dispatch

I made polymethods for fun a while back GitHub - johnmn3/dispacio: A predicate stack dispatch system for Clojure/Script

It’s similar to multimethods but let’s each method add its own dispatch function, rather than adding static values to be matched against the return value of a single dispatch function.

So you can use string? or int? or whatever predicate you want. Like:

(defp f-inc int? [x] (float (inc  x)))

(defp f-inc string? [x] (float (inc (read-string x))))

Or even dispatch off of specs or whatever else you want:

(require '[clojure.spec.alpha :as s])
(s/def :animal/kind string?)
(s/def :animal/says string?)
(s/def :animal/common (s/keys :req [:animal/kind :animal/says]))
(s/def :dog/tail? boolean?)
(s/def :dog/breed string?)
(s/def :cat/breed string?)
(s/def :animal/dog (s/merge :animal/common
                            (s/keys :req [:dog/tail? :dog/breed])))
(s/def :animal/cat (s/merge :animal/common
                            (s/keys :req [:cat/breed])))

With specs defined, make your polymethods:

(defp make-noise #(s/valid? :animal/dog %)
  [animal]
  (println "A" (:dog/breed animal) "barks" (:animal/says animal)))

(defp make-noise #(s/valid? :animal/cat %)
  [animal]
  (println "A" (:cat/breed animal) "meows" (:animal/says animal)))

And then you can dispatch on valid data:

(make-noise
  {:animal/kind "dog"
   :animal/says "woof"
   :dog/tail? true
   :dog/breed "retriever"})
;#_=> A retriever barks woof
(make-noise
  {:animal/kind "cat"
   :animal/says "brrr"
   :cat/breed "siamese"})
;#_=> A siamese meows brrr

Fun for when you want to experiment with different dispatch strategies based on the truthiness of arbitrary functions.

1 Like