What\'s the best way to detect whether an object is a Java primitive array in Clojure?
The reason I need this is to do some special handling for primitive arrays, which
(defn primitive-array? [o]
(let [c (class o)]
(and (.isArray c)
(.. c getComponentType isPrimitive))))
For particular cases, you could use something like the following:
(defn long-array? [o]
(let [c (class o)]
(and (.isArray c)
(identical? (.getComponentType c) Long/TYPE))))
To check for a byte array without the use of reflection you can do this:
(def ^:const byte-array-type (type (byte-array 0)))
(defn bytes? [x] (= (type x) byte-array-type))
Not exactly sure why, but you can even inline the byte-array-type with ^:const
.
Or plain old instance?
:
(instance? (RT/classForName "[B") thing)
Props to all the other answers. Here it is as a one-liner:
(def byte-array? (partial instance? (Class/forName "[B")))
For other primitives, refer to http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getName%28%29 (or the java spec). Or just do what Gerrit suggests with (type (xyz-array 0))
. Specifically you can use:
"[Z" boolean array
"[B" byte array
"[C" char array
"[D" double array
"[F" float array
"[I" integer array
"[J" long array
"[S" short array
Since performance was mentioned, here's a small benchmark result of running (time (dotimes [_ 500000] (byte-array? x)))
, and with byte-array-class
def'd
(def byte-array? (partial instance? (Class/forName "[B")))
78.518335 msecs
(defn byte-array? [obj] (instance? byte-array-class obj))
34.879537 msecs
(defn byte-array? [obj] (= (type obj) byte-array-class))
49.68781 msecs
instance?
vs type
= instance? wins
partial
vs defn
= defn wins
but any of these approaches will likely not be a bottleneck in performance.
you can use reflection once to get the class from the name, cache this and then compare the rest to that
(def array-of-ints-type (Class/forName "[I"))
(def array-of-bytes-type (Class/forName "[B"))
...
(= (type (into-array Integer/TYPE [1 3 4])) array-of-ints-type)
true
As pointed by Arthur Ulfeldt, you can use Class/forName
, for example, like here:
(def byte_array_class (Class/forName "[B"))
(defn byte-array? [arr] (instance? byte_array_class arr))
If you want to avoid magic strings like "[B"
when caching the classes, you can apply class
to an existing array object:
(def byte_array_class (class (byte-array [])))