8

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 "??????")?

2 Answers 2

15

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! it's a bit ugly but the Class/forName solution seems to be working just fine.
I've found that this only works if it's the first class in an extend-protocol definition. If not, Clojure 1.5.1 gives a java.lang.UnsupportedOperationException and complains that nth not supported on either the Character or the Symbol type.
2

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))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.