Clojure Protocol Namespaces
Importing and requiring Clojure protocols has its tricks. There are some edge cases you must be aware of when using them from separate namespaces.
First off, if you’re not familiar with Protocols, I suggest you go check out the documentation.
I’ll continue to use the examples from my recent blog post on Implementing Clojure Protocols. Here we have a protocol for defining how something Drives
.
(ns company.drives)
(defprotocol Drives
"a protocol for driving"
(drive [this throttle]))
Using a Protocol from a Different Namespace
In the concrete implementation of Car
we need to require the Drives
protocol like so.
(ns company.car
(:require [company.drives :refer [Drives]]))
(defrecord Car [top-speed]
Drives
(drive [_ throttle] (str "Spin wheels " (* top-speed throttle))))
Then in the namespace in which we are instantiating and using Car
, we’ll need to require the namespaces of the protocol and record. As well as import the record.
(ns company.core
(:require [company.car]
[company.drives :refer [drive]])
(:import company.car.Car))
(defn -main [args]
(println (drive (Car. 60.0) 0.4)))
What About Dashes?
There’s something tricky about using dashes in namespaces that I couldn’t find in any documentation.
Given these two facts about Java and Clojure:
- Java cannot have dashes in class names
- Clojure converts all dashes to underscores when compiling to Java
I was able to trial-and-error my way into a solution for dealing with dashes in protocols.
(ns company.school-bus
(:require [company.drives :refer [Drives]]))
(defrecord SchoolBus [top-speed]
Drives
(drive [_ throttle] (str "The wheels on the bus go " (* top-speed throttle))))
(ns company.core
(:require [company.car]
[company.drives :refer [drive]]
[company.school-bus])
(:import company.car.Car
company.school_bus.SchoolBus))
(defn -main []
(println (drive (Car. 60.0) 0.4))
(println (drive (SchoolBus. 45.0) 0.4)))
Notice the use of dash in the :require
but the use of underscore in the :import
. This is because the :import
is a Java import used for Java classes, and we must refer to our SchoolBus
record as a Java class.
Check out my article on Implementing Clojure Protocols for more information.