Be super-careful doing this. Java's array equality and hashCode are correct: 
since arrays are mutable, they are not values. So equals and hashCode are 
correctly identity-based.

Also, 1.2's vector-of lets you have vectors of primitives, which may give you 
the perf you need.

But, if you can ensure that the arrays will be used as values:

(ns key
  (:require [clojure.string :as str]))

(deftype Key [key]
  Object
  (equals [this other]
          (if (= (class this) (class other))
            (java.util.Arrays/equals ^ints key ^ints (.key ^Key other))
            false))
  (hashCode [this]
    (java.util.Arrays/hashCode ^ints key))
  (toString [this]
            (str/join \, (seq key))))

(defn int-key [coll]
  (Key. (int-array (count coll) coll)))

Stu

Stuart Halloway
Clojure/core
http://clojure.com

> If you don't do anything special, and create several Java array of bytes (for 
> example) and use them as keys in a Clojure map, the default hashCode and 
> equals implementation will cause two arrays with identical contents to be 
> treated as different keys in the map, unless they are also == in Java.
> 
> I'd like to use Java byte arrays as keys in Clojure maps, but haven't been 
> able to figure out how yet.  I know that java.util.Arrays/hashCode and 
> java.util.Arrays/equals have the behavior I want, so one way would be to get 
> Clojure to somehow use those methods when given the byte arrays as keys.  
> That led me to think of trying deftype to make my own type Key with the 
> desired implementation of hashCode and equals.  I'm using Clojure 1.2, and I 
> don't see how to give the appropriate type hints to declare that something is 
> a Java byte array.  Here is one attempt for Java int arrays instead of Java 
> byte arrays:
> 
> (definterface IKey
>   (^ints key [])
>   (equals [other-key] "Compare two Keys for value equality, i.e. same length 
> and same bytes in array value")
>   (hashCode [] "Return a hash code that is the same for equal keys, and 
> usually different for different keys"))
> 
> 
> (deftype Key [^ints key]
>   IKey
>   (key [this] key)
>   (equals [this other-key]
>     (let [^Key other other-key]
>       (java.util.Arrays/equals key (.key other))))
>   (hashCode [this]
>     (java.util.Arrays/hashCode key))
> 
>   Object
>   (toString [this]
>     (apply str (map char key))))
> 
> When I try to evaluate the deftype statement, I get an error like this:
> 
> java.lang.NoClassDefFoundError: java/lang/ints
> 
> Same error if I replace ^ints with #^ints.  If I leave out the type hints for 
> the field key completely, I get the following error when trying to evaluate 
> the deftype:
> 
> java.lang.VerifyError: (class: user/Key, method: hashCode signature: 
> ()Ljava/lang/Object;) Expecting to find object/array on stack
> 
> I'm not wedded to deftype as being part of the solution.  My real goal is as 
> high performance way of using Java byte/int/some-native-type arrays as map 
> keys, i.e. with no reflection warnings.
> 
> Thanks,
> Andy
> 
> 
> -- 
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with your 
> first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en




-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to