Strange decisions in Clojure – keyword inheritance

First, a disclaimer: the opinions on these posts are my own, and they reflect (for me) a design decision on the language that I don’t understand, specially considering other decisions that seems to contradict it. I also want to say that Clojure (and ClojureScript) is my favorite language, the one that I enjoy writing on my free time and professionally, so by no means this is a rant on the whole language!

Well, this is a new “series” on this blog: what is on the Clojure language that I don’t like, that I feel is out-of-place, and sometimes I can’t understand? In this first post, “keyword inheritance”. And what is that?

Clojure allows us to use derive to generate a “parent-child” inheritance against keywords. So, for example:

(isa? ::dog ::animal) ; => false
(derive ::dog ::animal)
(isa? ::dog ::animal) ; => true

This will change the way multimethods work too: so, for example, if derive is used and a multimethod expects an ::animal and you send a ::dog, it’ll use the implementation for ::animal:

(defmulti cry :type)
(defmethod cry ::animal [_] "Some animal crying")

(cry {:type ::wolf})
; Execution error (IllegalArgumentException) at user/eval152 (REPL:1).
; No method in multimethod 'cry' for dispatch value: :user/wolf
(cry {:type ::dog})
; => "Some animal crying"

(more…)