Extend the Clojure protocol to a primitive array

I would like to extend the Clojure protocol to work with primitive Java arrays.

(defprotocol PVectorisable (to-vector [a])) (extend-protocol PVectorisable ?????? (to-vector [coll] (Vectorz/create ^doubles coll)) java.util.List ... other implementations......) 

Is this possible, and if so, what is needed in the definition of the extended protocol above (instead of "??????")?

+4
source share
2 answers

The simplest solution probably captures the class programmatically with reflection.

 (defprotocol do-a-thing (print-thing [thing])) (extend-protocol do-a-thing (class (float-array 0)) (print-thing [_] (println "it a float array"))) 

Java arrays follow odd names. For example, the float array has the value [F If you try to use it directly in the REPL, it will suffocate from the unrivaled [ . However, you can still use this name, for example, Class/forName .

 (defprotocol do-another-thing (print-another-thing [thing])) (extend-protocol do-another-thing (Class/forName "[F") (print-another-thing [_] (println "it still a float array"))) 

In this article, we will take a closer look at array classes.

+7
source

As noted by hadronzoo, a Class / forName solution only works if it is the first defprotocol definition that restricts the solution to only one array type per protocol (or you need to make several defprotocol definitions). This can be done to work with several types of arrays using a macro, to avoid the problem when the reader could not parse the characters of the array:

 (defprotocol ISample (sample [_])) (defmacro extend-protocol-arrays [] (let [ba (symbol "[B") ia (symbol "[I") oa (symbol "[Ljava.lang.Object;")] `(extend-protocol ISample ~ba (sample [this#] (println "Byte Array")) ~ia (sample [this#] (println "Int Array")) ~oa (sample [this#] (println "Object Array"))))) (extend-protocol-arrays) (sample (byte-array 0)) (sample (int-array 0)) (sample (make-array Object 0)) 
+1
source

All Articles