Search code examples
clojurecomposition

How do I compose two deftypes into a new deftype when they all live in different files?


The following works in the repl:

(defprotocol MyProtocol
  (foo [this]))
(deftype A []
  MyProtocol
  (foo [this] "a"))
(deftype B []
  MyProtocol
  (foo [this] "b"))
(deftype C []
  MyProtocol
  (foo [this] (str (foo (A.)) (foo (B.)))))

When I try to move each instance to a separate file to reduce coupling, then I get the following error on C: "Unable to resolve symbol: foo in this context"

Sample layout:

;; my_protocol.clj
(ns my-protocol)
(defprotocol MyProtocol
  (foo [this]))

;; type_a.clj
(ns type-a
  (:require my-protocol :refer [MyProtocol])
(deftype A []
  MyProtocol
  (foo [this] "a"))

;; type_b.clj
(ns type-b
  (:require my-protocol :refer [MyProtocol])
(deftype B []
  MyProtocol
  (foo [this] "b"))

;; type_c.clj
(ns type-c
  (:import [type_a A]
           [type_b B])
  (:require my-protocol :refer [MyProtocol])
(deftype C []
  MyProtocol
  (foo [this] (str (foo (A.)) (foo (B.)))))    

Solution

  • (ns type-a
      (:require my-protocol :refer [MyProtocol])
    

    You refer to the protocol, but never to foo, so when you attempt to call foo the compiler doesn't know what you mean. Instead write:

    (ns type-a
      (:require my-protocol :refer [MyProtocol foo])