I am writing a class that needs to have a unique hashcode based on two of its fields and I wanted to know whether XORing the 2 fields hashcodes is enough to generate a unique and consistent hashcode for my object?
class _TypeMatch{
final Type _potentialSubtype;
final Type _supertype;
int _cachedHashCode;
_TypeMatch(this._potentialSubtype, this._supertype){
_cachedHashCode = _potentialSubtype.hashCode ^ _supertype.hashCode;
}
int get hashCode => _cachedHashCode;
bool operator ==(other){
return other is _TypeMatch && _cachedHashCode == other._cachedHashCode;
}
}
I have seen this question here which seems to suggest that XORing two other hashcodes is the correct thing to do but they multiiply each hashcode by 2 large primes first, and I wasnt sure why or if this was necessary. I'm primarily concerned that for two Types A and B:
new _TypeMatch(A, B) == new _TypeMatch(A, B) // is true for all A and B
and that the calculation of the combined hash is as efficient as possible as creating a new _TypeMatch is going to be a core part of the system and so any performance inefficiencies will be felt drastically throughout the system.
Hashcodes are used for example in a hashmap or hashtable to distribute the stored key/values equally into 'slots'. One slot can contain many key/values but by using the hashcode it is easy and quick to find a slot in the map and from there to look for a concrete key/value in a much smaller set of values. This improves the speed when searching in a map very fast no matter what kind of data type is used for the key. When the hashcode would change for a stored key/value the value can't be retrieved anymore by key.
You could just use 1
as hashcode for every object but this would ruin the performance.
You get the opposite effect (optimal performance) with a good distribution (different hashcodes for different objects) but there is a limit. When you use for example a 32bit integer type for the hashcode the number of possible hashcodes is limited.
See http://en.wikipedia.org/wiki/Hash_table for more details.
There are many more use cases for hashes though.
I suggest using the hash2
method from quiver package
https://github.com/google/quiver-dart/blob/master/lib/src/core/hash.dart#L26
You can use it like
import 'package:quiver/core.dart' show hash2;
@override
int get hashCode => hash2(val1, val2);
They use this code to combine hash codes
int _combine(int hash, int value) {
hash = 0x1fffffff & (hash + value);
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
update
(from my comment below the question)
The hashcode
isn't supposed to be unique. That it doesn't change is important though. Equal objects should return the same hashcode but that doesn't mean that different objects need to have different hashcodes. You shouldn't use the hashCode for checking equality.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With