7

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.

Community
  • 1
  • 1
Daniel Robinson
  • 13,806
  • 18
  • 64
  • 112
  • What do you mean by **unique**? 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. – Günter Zöchbauer Oct 30 '14 at 09:21
  • what is the purpose of hashcodes if not checking for uniqueness/equality? I thought that 1.hashCode == 1.hashCode is true as is "yo".hashCode == "yo".hashCode – Daniel Robinson Oct 31 '14 at 10:20
  • My english sucks and my sentences are ponderous therefore my comments tend to become too long for the comment field ;-). I updated my answer instead. – Günter Zöchbauer Oct 31 '14 at 10:32
  • One hashcode should be used either for equality or identity, but *not both at the same time*; equality and identity are two different properties. – Burhan Khalid Feb 28 '19 at 06:36

1 Answers1

5

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.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 2
    As Günter explains in his comment on the original question, the `hashCode` contract does not require an object's hash code to be unique, only that two objects that are `==` to each other must have the same `hashCode`. If you need unique hash codes, you shouldn't rely on Dart's built-in `hashCode`s, but roll your own to ensure uniqueness. – Tonio Oct 30 '14 at 15:13