Skip to content

Comment on Why Java's Object.hashCode() is unsafe for use in distributed systemsparent

Comments

I mean value semantics in the standard sense, http://en.wikipedia.org/wiki/Value_semantics . You're correct that relatively few classes in the java standard library do so.

There is no convention that hashCode() should be stable across processes; the only thing that could reasonably define such a convention is the javadoc of Object#hashCode, which explicitly states otherwise. More pragmatically, there is an important set of objects, widely used in distributed systems, whose implementation of hashCode() is not stable across processes (namely protocol buffers objects). So distributed frameworks can't and shouldn't assume hashCode() is stable across processes.

Okay, let's take this one by one:

Value semantics are a case where the identity shouldn't really exist at all, as all that matters is equivalence. There is a lot of room there in between where equivalence has meaning but identity can still play a role.

Arguably in Java only the native types (which aren't part of the Java standard library) really embody this, with their wrappers and String barely getting a nod, and Collections totally don't fit the bill. IIRC part of the language definition refers to the fact that all object have reference semantics.

Protocol Buffers are meant to be used like as a memento [http://en.wikipedia.org/wiki/Memento_pattern]. At most you should have a wrapper object providing behaviours like equivalence (in fact with Hadoop, I do this all the time with them, which is kind of a must anyway as Protocol Buffers don't implement Writable, let alone WritableComparable, etc.). Protocol Buffers very much don't have behaviour beyond serialization, which is exactly why they shouldn't have equivalence implementations. Consequently, if you are invoking equals(), hashCode(), etc. on them, "you are doing it wrong".

You're right though that there isn't a strict convention about hashCode() being stable across processes. It's more like a corollary that stems from implementing equals(Object) in terms of an object's equivalence. When you define equivalence for an object, you implement equals(Object) to represent that notion. Because of the contract that hashCode() has with equals(Object), the only cases where hashCode() shouldn't be stable across processes is where the objects actually aren't equivalent across processes.

This should fit quite well with the objectives of a distributed system. In particular, if you are defining something as a "key", it must have a very clear notion of equivalence for it, and in that context it not only should be stable across processes, it needs to be stable across the entire system. If you don't implement that logic in equals(Object), you're violating that contract. This means your hashCode() method needs to reflect that stability across processes. I can come up with some ways of screwing up hashCode() in that context while still avoiding breaking the contracts, but they're all contrived and in practice I've never seen anyone actually do that.

Seriously, if you are running in to these issues, you have bigger problems in the design.

> Arguably in Java only the native types (which aren't part of the Java standard library) really embody this

To be clear: "embody this" meant "Value Semantics", not the in-between space.

AboutSource Built by g1lg1l

Hackerly is an independent reader for Hacker News, built on the public HN API. Not affiliated with Y Combinator.