Hendekagon
Hendekagon

Reputation: 4643

Multimethods in Clojure, polymorphism, big switches

I have read the pattern (defmulti multi (fn [t] (cond (seq? t) :seq (map? t) :map (vec? t) :vec ... in lots of Clojure code here and there, which is basically a switch (if I add a type, I have to add a new clause) but more verbose. Is there not a way to say (defmethod seq, (defmethod vec (defmethod map.. etc ? It must be a very common thing to do. I'm aware that it's possible to manually define hierarchies, but what about common Clojure types like sequence, vector, map...would they have to be defined for each program which dispatched on type ? Please show me how I'm missing the point!

edit: ok I thought I could say (defmulti mymulti type) then (defmethod clojure.lang.PeristantSomething... etc, but that's clumsy as it refers to java classes, but I want to refer to some quality of the 'type' like whether it's sequential or associative

Upvotes: 1

Views: 345

Answers (2)

Jonas
Jonas

Reputation: 19642

Dispatching on type works well for this:

user> (import '[clojure.lang Associative Sequential])
user> (defmulti foo type)
#'user/foo

user> (defmethod foo Associative [x] :map)
#<MultiFn clojure.lang.MultiFn@7e69a380>

user> (foo {:x 1})
:map
user> (foo ())
; fails, a list is not associative

user> (defmethod foo Sequential [x] :seq)
#<MultiFn clojure.lang.MultiFn@7e69a380>
user> (foo ())
:seq
user> (foo [])
; fails, a vector is both sequential and associative

user> (prefer-method foo Sequential Associative)
#<MultiFn clojure.lang.MultiFn@7e69a380>
user> (foo [])
:seq

Note that both Sequential and Associative are interfaces and not concrete classes.

Upvotes: 3

number23_cn
number23_cn

Reputation: 4619

choose dispatched function is type or class.

Upvotes: 0

Related Questions