Re: hashCode
On 8/29/2012 2:06 PM, Daniel Pitts wrote:
On 8/28/12 5:02 PM, markspace wrote:
On 8/28/2012 4:33 PM, Daniel Pitts wrote:
interface Hasher<Type> {
int hash(Type t);
Not really seeing how this is a good idea. How would you implement this?
So, that would change HashMap to take a Hasher<? super K> instance in
its constructor.
This is the problem; Map (and HashMap) were desired to be spec'd as
taking Object, not a subclass.
Actually, they are Generic, so they are not spec'd to take Object, but
to take a specific subtype defined at compile time. At least, now that
they have the addition of Generics. Pre-generics, they still had
Comparators which had the same behavior that I'm describing, but instead
of defining buckets, they define an ordering. See below.
Actually, "take" is insufficiently specific. A Map<K,V>
has a put() method with K,V parameters, and a putAll() method
with a Map<? extends K, ? extends V> parameter. To that extent,
Map<K,V> "takes" K.
But Map<K,V> *also* has get() and remove() and containsKey()
methods with Object parameters, not K parameters. (It also has a
containsValue() method taking Object, not V.) So insofar as
these methods are concerned, Map<K,V> "takes" Object.
A default Hasher<Object> could be implemented to use
System.identityHashCode and == for the common use-case.
Again not seeing how you'd actually use that to put an object in a Map.
Example usage:
++++
// MyKeyHasher implements Hasher<MyKey>
Map<MyKey, MyValue> map=new HashMap<MyKey,MyValue>(new MyKeyHasher());
map.put(myFirstKey, myFirstValue);
map.put(mySecondKey, mySecondValue);
++++
This could sort of work, but not very well. As I wrote some
<hunt, hunt, hunt, ah!> seventeen days ago in this thread:
I don't think a HashCalculator interface along
the lines of Comparable would save the day.
The difficulty is that an external Hasher would have no access to
private fields of MyKey. That may seem a small drawback, since it
is rare to have a contributor to an object's "value" that is not
at the very least accessible through a getter. The Hasher might
need to make method calls where today's built-in hashCode() just
makes field references, but -- hey, how bad could that be?
IMHO, it could be pretty bad. Take java.lang.String, for
example: As things stand today hashCode() inspects the "value"
of the String, and everything it uses would be accessible to a
Hasher<String>. But hashCode() then caches the computed value
in a private field within String to avoid recomputing it on every
subsequent call! Could Hasher<String> do the same? How?
Okay, so the implementor of String perceives the problem and
decides that String itself will provide a default Hasher<String>
implementation. (This might be a static nested class, but it'd
probably be more efficient to have String implement Hasher<String>
directly, so every String is its own Hasher.) And the implementor
of BigInteger does the same, and so does the implementor of URL,
and of File, and of -- Hey, wait a minute! We're right back where
we began, except with more overhead and more verbiage!
--
Eric Sosman
esosman@ieee-dot-org.invalid