Avoiding reflection/hinting with byte-array.

711 views
Skip to first unread message

David Brown

unread,
Nov 7, 2009, 10:41:21 AM11/7/09
to clo...@googlegroups.com
I can't figure out how to avoid reflection, in the 'update' method of
MessageDigest. It is overloaded on a single argument with either
'byte', 'byte[]', or 'java.nio.ByteBuffer'.

(import '(java.security MessageDigest))
(set! *warn-on-reflection* true)

The compiler didn't seem to like a tag that wasn't actually a class
name:

(def byte-array-class
(class (make-array Byte/TYPE 0)))

;; "Unable to resolve classname: byte-array-class"
(defn update1
[#^MessageDigest md #^{:tag byte-array-class} item]
(.update md item))

And it seems to have no effect if I expand it as the tag:

;; "call to update can't be resolved."
(defn update2
[#^MessageDigest md #^{:tag (class (make-array Byte/TYPE 0))} item]
(.update md item))

In this particular case, I was able to work around the issue one of
two ways, basically by using a different type.

(defn workaround
[#^MessageDigest md item]
(.update md item 0 (count item)))

(defn workaround2
[#^MessageDigest md item]
(.update md (java.nio.ByteBuffer/wrap item)))

Any ideas? BTW, my real use case is in a defmethod, where I handle
several other types for the update.

Thanks,
David

Chouser

unread,
Nov 7, 2009, 11:48:32 AM11/7/09
to clo...@googlegroups.com
On Sat, Nov 7, 2009 at 10:41 AM, David Brown <clo...@davidb.org> wrote:
>
> I can't figure out how to avoid reflection, in the 'update' method of
> MessageDigest.  It is overloaded on a single argument with either
> 'byte', 'byte[]', or 'java.nio.ByteBuffer'.
>
>   (import '(java.security MessageDigest))
>   (set! *warn-on-reflection* true)
>
> The compiler didn't seem to like a tag that wasn't actually a class
> name:
>
>   (def byte-array-class
>     (class (make-array Byte/TYPE 0)))
>
>   ;; "Unable to resolve classname: byte-array-class"
>   (defn update1
>     [#^MessageDigest md #^{:tag byte-array-class} item]
>     (.update md item))

Right, :tag values should be symbols, not classes or instances of
those classes. Most of those symbols name actual Java classnames
but a few other symbols are supported, mostly for arrays of
primitives:

objects Object[].class;
ints int[].class;
longs long[].class;
floats float[].class;
doubles double[].class;
chars char[].class;
shorts short[].class;
bytes byte[].class;
booleans boolean[].class;

This should work:

(defn update1 [#^MessageDigest md, #^bytes item]
(.update md item))

--Chouser

David Brown

unread,
Nov 7, 2009, 2:57:30 PM11/7/09
to clo...@googlegroups.com
On Sat, Nov 07, 2009 at 11:48:32AM -0500, Chouser wrote:

>This should work:
>
> (defn update1 [#^MessageDigest md, #^bytes item]
> (.update md item))

This does seem to work, thanks.

Any reason that 'doubles' is also defined as an array cast function,
but 'bytes' is not?

David

Chouser

unread,
Nov 7, 2009, 3:13:30 PM11/7/09
to clo...@googlegroups.com

I don't know of any deep reason.

Not only bytes, but also array-cast functions don't exist for
chars, shorts or booleans.

Also there are factory functions for several primitive array
types, but char-array, short-array, byte-array, and
boolean-array don't exist.

--Chouser

Rich Hickey

unread,
Nov 10, 2009, 6:52:44 AM11/10/09
to clo...@googlegroups.com
There is no deep reason. Patch welcome for unifying the array support
for primitives.

Rich
Reply all
Reply to author
Forward
0 new messages