5

First I wish to state that I'm aware of the javadoc of java.lang.Object.hashCode() and thus there's no need to mention it again.

What I'm asking is: Why isn't java.lang.Object.hashCode() moved into a seperate interface named (probably) Hashable? Like `java.lang.Comparator'?

To me, hashCode() is only used in hash-dependent data structures like HashMap or HashTable, which a) are not used in every application b) are often used with very few types of keys like String or Integer and not with a InputStream (or something like it).

I know that I do not have to implement hashCode() for every class of mine, however, isn't adding a method to a class at the cost of performance to some extent? Especially for java.lang.Object - the superclass of every class in Java.

Even if special optimization is done within the JVM so that the lost of performance can be ignored, I still think that it's unwise to provide every Object with a behavior that is not frequently implemented at all. According to the Interface Segregation Principle:

No client should be forced to depend on methods it does not use.

I did some searches in the web and the only related page I could find is this.

The first answer expressed (partly) the same idea as mine, and some others tried to answer the question, saying mainly that "hashCode() for every Object enables storage of object of any type in HashMap", which I take as not satisfactory.

I here propose my own solution, which satisfies both the Interface Segregation Principle and the ability to store anything in a HashMap without adding much complexity the whole system:

  1. Remove hashCode() from java.lang.Object.
  2. Let there be an interface Hashable, containing hashCode() with the same contract as the former java.lang.Object.hashCode().
  3. Let there be an interface HashProvider with a type parameter T containing provideHashCode(T t) to provide a hash code for an object. (Think of Comparator<T>).
  4. Let there be an implementation of HashProvider<Object> called DefaultHashProvider which generates the hash code for any Object using the current implementation of Object.hashCode(). (As for Java 8, Object.hashCode() is a native method, I expect DefaultHashProvider.provideHashCode() to return the same thing for any Object)
  5. Modify constructors of HashMap and HashTable so that everything can be stored in them by:
    1. Using the provideHashCode() if a HashProvider is specified.
    2. Using the hashCode() if its underlying elements implement Hashable.
    3. Using DefaultHashProvider otherwise.

I believe that this is possible in practice because it's just a variation of the system of Comparable, Comparator and TreeMap.

And let my repeat my question:

Considering that the Java development team should not be unable to come up with a solution similar to mine, is there any good reason for not doing so? Are there some advanced considerations that I'm currently unaware of? I have the following hypotheses, does any of them approach the correct answer?

  1. Some language features required by this solution, like generic types, are available only well after the very beginning of Java - since 1.5. However, I would argue that Comparator, Comparable along with TreeMap exist since 1.2, can't the technique used to write them be adapted to HashMap?
  2. hashCode() is used somewhere within the JVM and therefore it requires every Object to have a hash code. However this can also be available using DefaultHashProvider.provideHashCode() (or its native implementation) for non-hashables.
std4453
  • 528
  • 7
  • 12
  • 3
    a simple note aside of it making sense or not: It´s not changable as it would break backward compatibility. – SomeJavaGuy Oct 30 '17 at 13:14
  • 1
    Why not asking the same for every `Object` method then? – Jean-Baptiste Yunès Oct 30 '17 at 13:14
  • In case of `Comparator`, being comparable doesn't makes sense for every object, but being Hashable does. – Nima Ghotbi Oct 30 '17 at 13:17
  • @Jean-BaptisteYunès I do find that most methods in `Object` are appropriate, like `getClass()` etc. I'm only asking about this specific one, `hashCode()`. – std4453 Oct 30 '17 at 13:18
  • @SomeJavaGuy So is it really a design mistake, placing `hashCode()` inside `Object`? Just for compatibility this cannot be amended? – std4453 Oct 30 '17 at 13:22
  • It won't be changed, no. Some libraries provide a "hashable" mechanism for these kinds of operations, but the JDK won't ever move `hashCode` out of `Object`. There are far more minor oddities that still remain in there, so something this big would never fly. – Kayaman Oct 30 '17 at 13:25
  • But your args like "hashcode is only used in..." can't be translated for every Object method. Anyway. "design mistake" maybe, but Java is an old language now,and these kind of considerations are much newer. And, YES compatibility is a very good argument too. – Jean-Baptiste Yunès Oct 30 '17 at 13:26
  • @std4453 it might be and one can argue about it, but removing the `hashCode` from `Object` is a big nono, as the java version forcing these wouldn´t be able to execute java code compiled in lower version (one of the main goals is the ability to execute code done in lower java version). That´s the point for me where one could theoretically talk about it beeing structured well enough, but it´s simply impossible to change. This might lead to the same type of discussion as [the Discussion why one is able to execute static methods on object instances](https://stackoverflow.com/q/610458/1799530) – SomeJavaGuy Oct 30 '17 at 13:28
  • 4
    `hashCode` is also part of the contract for `equals` so you can't move it out of `java.lang.Object` – Lothar Oct 30 '17 at 13:29
  • 3
    Every software project has some legacy. Why are concerned about `hashCode` only? There is a method called `finalize` which is considered harmful and not recommended for use. It's still there! For most of the "why" questions in Java you will get an answer - backward compatibility. Which is (or at least was) an important selling point. If you want more info one option is to use twitter - many of java platform developers/contributors are there. You can post this SO link there and mention someone. – Admit Oct 30 '17 at 13:31
  • @Admit [`java.lang.Object.finalize()`](https://docs.oracle.com/javase/9/docs/api/java/lang/Object.html#finalize--) is deprecated in Java 9, but yes, it will never be removed because of backward compatibility. – Jesper Oct 30 '17 at 13:36
  • Saying "is only used in hash-dependent data structures like HashMap or HashTable" ignores that these structures allow fast access to instances. It means that internal Java systems can organize all Java objects efficiently instead of just instances that implement Hashable. – JimW Oct 30 '17 at 18:08
  • @JimW Well I think I've stated this clear enough... I understand that some applications might want every `Object` to have a hash code, however this does not mean that `hashCode()` must be in `Object` - it can be somewhere else, like in the solution I've proposed in the question. – std4453 Oct 31 '17 at 11:09
  • I guess you didn't read my comment entirely or maybe you're just a troll, but I mentioned it's likely important to the JVM, the internal Java systems that are written in guess what, Java! It's likely that for efficiency sake the JVM wants every object to be Hashable. Every Object, not just objects that implement Hashable. – JimW Oct 31 '17 at 13:35

0 Answers0