12

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 might look something like:

  (if (byte-array? object)
    (handle-byte-array object))

It's in a fairly performance-sensitive piece of code so I'd rather avoid reflection if at all possible.

1
  • 1
    Not sure what the Clojure code would be, but you could create an empty array for every primitive type, call getClass() on those, and cache the results. The Class object should be the same for every array of that primitive type – you'd compare the cached ones with object.getClass(). (getClass() shouldn't really be a slow call) Commented Feb 1, 2012 at 3:45

7 Answers 7

11

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
Sign up to request clarification or add additional context in comments.

2 Comments

Nice, like the idea of caching the primitive array classes. Though it does strike me as a bit off that these aren't already defined somewhere in Java!
"[J" for longs is even more endearing, isn't it? Also, whoever came up with the unmatched opening brackets in .toString return values, anytime I learn their name, my pitchfork will be ready. It breaks paredit for me all the time, not to mention the effect on my psyche. (Replacing print-method for all the relevant cases may or may not be feasible -- my current gut feeling is not.)
7
(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))))

1 Comment

7

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.

Comments

5

Or plain old instance?:

(instance? (RT/classForName "[B") thing)

2 Comments

What alias are you using for RT? You mean (Class/forName "[B") right?
@DavidJames RT is clojure.lang.RT.
5

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

1 Comment

Even simpler: (def byte-array-class (class (byte-array 0))). (No underscores either!)
3

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.

Comments

2

Since Clojure 1.9, you can use bytes? bytes? doc link

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.