Ayende @ Rahien

My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:


+972 52-548-6969

, @ Q c

Posts: 6,125 | Comments: 45,488

filter by tags archive

Relying on hash code implementation is BAD – part II

time to read 2 min | 325 words

To be truthful, I never thought that I would have a following for this post 4 years later, but I run into that today.

The following is a part of an integration test for NH Prof:

Assert.AreEqual(47, alerts[new StatementAlert(new NHProfDispatcher())
	Title = "SELECT N+1"

I am reviewing all our tests now, and I nearly choked on that one. I mean, who was stupid enough to write code like this?  I mean, yes, I can understand what it is doing, sort of, but only because I have a dawning sense of horror when looking at it.

I immediately decided that the miscreant that wrote that piece of code should be publically humiliated and  chewed on by a large dog.

SVN Blame is a wonderful thing, isn’t it?


Hm… there is a problem here.

Actually, there are a couple of problems here. One is that we have a pretty clear indication that we have a historic artifact here. Just look at the number of version that are shown in just this small blame window. This is good enough reason to start doing full fledged ancestory inspection. The test has started life as:

public class AggregatedAlerts:IntegrationTestBase
	public void Can_get_aggregated_alerts_from_model()

		var alerts = observer.Model.Sessions[1].AggregatedAlerts;
		Assert.AreEqual(47, alerts["SELECT N+1"]);
		Assert.AreEqual(21, alerts["Too many database calls per session"]);

Which I think is reasonable enough. Unfortunately, it looks like somewhere along the way, someone had taken the big hammer approach to this. The code now looks like this:

Assert.AreEqual(47, alerts.First(x => x.Key.Title == "SELECT N+1"));

Now this is readable.

Oh, for the nitpickers, using hash code evaluation as the basis of any sort of logic is wrong. That is the point of this post. It is a non obvious side affect that will byte* you in the ass.

* intentional misspelling



btw, this is not relying on a particular hash code but on the fact that gethc and equals are properly implemented, so that:

a.eq(b) => a.gethc() == b.gethc()

a.gethc() != b.gethc() => !a.eq(b)

and that eq and gethc are taking into account all relevant fields. however an "action" kind of object (without knowing exactly what your statementaction does) is probably not the right kind of hash code provider. gethc should only be implemented for value object imo. i also think it is a mistake in the framework design that every object has equals and gehashcode methods. that is clearly something that not every object can and should support.

Ayende Rahien


Not really.

If you don't have that, you can't write hash table or dictionary.

Bill Pierce

It is not obvious from your posts, excluding the readability of the code, what the non obvious side affects are of using GetHashCode in this way. Can you enlighten me?

Ayende Rahien


My main concerns arereadability and sensability


Agreed, it doesn't read well that alerts["SELECT N+1"] means get the alert with the title "SELECT N+1" especially with the one below it "alerts["Too many database calls per session"]" which looks like your using the [] to set a message not select a title.

Though in my eyes, it's more of a case of bad titling. :P But then using more code like titles to reference a full alert would probably read just as cryptic.


String.GetHashCode() returns different values when running in a 32-bit or 64-bit image.

Now, if you serialized the value somewhere in a file format...

Yes, it happened. No comments please ;)

Ayende Rahien


That is actually something that you should be worried about in a mixed 32 & 64 bits env.

Most distributed caches does the naive thing and use GetHashCode to get the hashcode for the key lookup.

Granted, there aren't that many mixed bits mode, but it is important to know

Comment preview

Comments have been closed on this topic.


  1. The design of RavenDB 4.0: Physically segregating collections - 10 hours from now
  2. RavenDB 3.5 Whirlwind tour: I need to be free to explore my data - about one day from now
  3. RavenDB 3.5 whirl wind tour: I'll have the 3+1 goodies to go, please - 4 days from now
  4. The design of RavenDB 4.0: Voron has a one track mind - 5 days from now
  5. RavenDB 3.5 whirl wind tour: Digging deep into the internals - 6 days from now

And 12 more posts are pending...

There are posts all the way to May 30, 2016


  1. The design of RavenDB 4.0 (14):
    03 May 2016 - Making Lucene reliable
  2. RavenDB 3.5 whirl wind tour (14):
    04 May 2016 - I’ll find who is taking my I/O bandwidth and they SHALL pay
  3. Tasks for the new comer (2):
    15 Apr 2016 - Quartz.NET with RavenDB
  4. Code through the looking glass (5):
    18 Mar 2016 - And a linear search to rule them
  5. Find the bug (8):
    29 Feb 2016 - When you can't rely on your own identity
View all series


Main feed Feed Stats
Comments feed   Comments Feed Stats