0

Is it possible to dispatch based on a namespaced map namespace i.e. #:<this-thing>{}? Without hacks like printing or inspecting key prefixes?

I consider the last one hacky because a key prefix can be overridden:

(:qux/bar #:qux{:bar :baz}); => :baz
(:foo/bar #:qux{:foo/bar :baz}); => :baz
(:qux/bar #:qux{:foo/bar :baz}); => nil
JAre
  • 4,666
  • 3
  • 27
  • 45

2 Answers2

3

A map might contain all qualified keyword keys from a certain namespace, or it may contain a mix of unqualified keys or qualified keys from multiple namespaces. Here's a function to get the set of all namespaces (as keywords) from qualified keyword keys in a map:

(defn key-namespaces
  "Returns set of all namespaces of keys in m."
  [m]
  (->> (keys m)
       (keep (comp keyword namespace))
       (set)))

Now you can use that as a dispatch-fn on a multimethod:

(defmulti do-thing key-namespaces)
(defmethod do-thing #{:foo} [m] (prn m))
(do-thing #:foo{:bar 1})
;; #:foo{:bar 1}
(foo {:bar/bar 1})
;; no multimethod found exception

You could specify multiple namespace prefixes in that set, or you could use a different dispatch-fn based on your use case.

Taylor Wood
  • 15,886
  • 1
  • 20
  • 37
1

This is not possible as this is just the visual representation of the map produced by writer. You would have to do the checks by yourself if all the keys in your map share the same namespace. Also the last example won't be produced by the writer - it will emit namespaced map literal only when all the keys share the same namespace.

Piotrek Bzdyl
  • 12,965
  • 1
  • 31
  • 49