Reputation: 397
I have a protocol in a crossover namespace:
(ns xxx.shared.interfaces)
(defprotocol ITimer
(seconds [timer] "Return time in seconds since timer began"))
I have an implementation for Clojure:
(ns xxx.time
(:require [xxx.shared.interfaces :refer [ITimer]]))
(defrecord Timer [start-nanos]
ITimer
(seconds [timer] (double (/ (- (System/nanoTime) (:start-nanos timer))
1000000000))))
The problem is that when I use this code in some Clojure code, having required the xxx.time
namespace with :refer :all
it complains it can't find seconds
:
Unable to resolve symbol: seconds in this context
First of all, is it possible to share protocols in this way?
Secondly, any idea how I can make this work?
Thirdly, is this actually a good way to go about this kind of code sharing? Ideally I'd like to share the record too, but it relies on Java code, so I'd need to break that out into a function. Would that be a better way to go about this?
Thanks!
Upvotes: 2
Views: 328
Reputation: 84331
seconds
is defined in xxx.shared.interfaces
, so that's what you need to :require
/ :use
to be able to call it:
(ns foo
(:require [xxx.shared.interfaces :refer [seconds]]))
;; (seconds ...) will now work
To elaborate, a defprotocol
expression creates a Var holding the protocol, an underlying JVM interfaces on the JVM side (no counterpart to this on the ClojureScript side) and a Var for each of the protocol methods. The protocol methods can then be called through those Vars just like any other Clojure function.
When you implement a protocol for a record / type, as you do in your xxx.time
namespace, you don't even need to pull in those Vars if you don't actually call the methods (a separate issue from providing implementations). Similarly, a namespace which needs to call the protocol methods, but doesn't much care about the particular types of objects it calls them on, would only need to pull in the protocol-defining namespace and use the relevant Vars and would not need to :require
any implementing namespaces.
Upvotes: 6