Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extend Clojure protocol to a primitive array

I'd like to extend a Clojure protocol to deal with Java primitive 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 needs to go in the extend-protocol definition above (in place of "??????")?

like image 693
mikera Avatar asked Dec 18 '12 01:12

mikera


2 Answers

The simplest solution is probably grabbing the class programatically with reflection.

(defprotocol do-a-thing
 (print-thing [thing]))

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

Java's arrays go by some odd names. The float array, for example, is [F. If you try to use that directly in the REPL, it'll choke on the unmatched [. However, you can still use this name with, 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's still a float array")))

This article goes into more detail about array classes.

like image 95
Beyamor Avatar answered Sep 21 '22 12:09

Beyamor


As noted by hadronzoo, the Class/forName solution only works if it's the first definition of defprotocol, which limits the solution to only one array type per protocol (or having to make multiple defprotocol definitions). This can be made to work with multiple array types with a macro to avoid the problem of the reader not being able to parse the array symbols:

(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))
like image 45
optevo Avatar answered Sep 23 '22 12:09

optevo