Search code examples
clojureprimitive

Clojure - Reflection Warning with primitive array .length


I'm having some trouble trying to use instance methods on a java float array in clojure. Specifically, the following code gives a reflection warning on the call to .length

(defn make-matrix
  ([^floats fs]
   (let [len-fs (.length fs)]
     (cond (>= len-fs 16) (Matrix4. fs)
           (>= len-fs 9)  (Matrix3. fs)
           :else (throw (IllegalArgumentException. (str "Array must have at least 9 elements (found" len-fs ")")))))))

By my understanding, the type-hint should eliminate the need for reflection to resolve the call to .length. What am I missing?


Solution

  • Arrays on the JVM are not quite like regular objects and their lengths are not obtained through a field lookup, but rather through a specialized opcode arraylength. Java's array.length notation is just syntactic sugar that compiles down to this opcode. Therefore, (.length fs) will simply fail at runtime, because fs will be found to have neither a length method nor a length field (assuming it is in a fact an array).

    Thus, you should use the clojure.core/alength function:

    (alength fs)
    

    Without a type hint, this will result in a reflective call; with a type hint, it will be a direct call to a static method returning fs.length (in Java notation).