Welcome! Please see the About page for a little more info on how this works.

+1 vote
in Clojure by
retagged by

If you accidentally specify a protocol multiple times in a deftype form, some method implementations of that protocol may be omitted.


(defprotocol P (f [this]) (g [this]))

(deftype T []
  (f [this] :F)
  (g [this] :G))

(def t (->T))

(f t)
;; Execution error (AbstractMethodError) at user/eval187 (REPL:1).
;; Receiver class user.T does not define or inherit an implementation of the resolved method 'abstract java.lang.Object f()' of interface user.P.

(g t) ;=> :G

You can confirm by macroexpanding the deftype form that some of the method implementations are ignored:

(macroexpand '(deftype T [] P (f [this] :F) P (g [this] :G)))
;=> (let* [] (deftype* user/T user.T [] :implements [user.P clojure.lang.IType] (g [this] :G)) (clojure.core/import user.T) (clojure.core/defn ->T "Positional factory function for class user.T." [] (new user.T)) user.T)

It seems like the root cause boils down to parse-impls:

(#'clojure.core/parse-impls '(P (f [this] :F) P (g [this] :G)))
;=> {P ((g [this] :G))}

In my opinion, it would be nice if deftype would check to see if the same protocol is specified more than once and throw an error if so. Otherwise the method implementations should not be ignored without any warning, I think.

1 Answer

+1 vote
selected by