Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dart, is xoring two hashcodes always going to return a new unique hashcode?

Tags:

hashcode

dart

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.

Update

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.

like image 951
Daniel Robinson Avatar asked Oct 30 '14 08:10

Daniel Robinson


1 Answers

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.

like image 74
Günter Zöchbauer Avatar answered Oct 16 '22 11:10

Günter Zöchbauer