bodar/totallylazy

com.googlecode.totallylazy.Eq implements equals but not hashCode

Closed this issue · 5 comments

This might mean that equals and hashCode have inconsistent behaviour

Eq doesn't change the default behaviour from Object, but allows you to write typesafe multi method implementations instead.

Out of interest Java got it wrong, not all things that are equal are hashable but all things hashable should support equality.

Can you explain how Eq doesn't change the default behaviour from Object?

I am having a bit of trouble following multi.methodOption.

Am I right in thinking that it is possible to annotate one or more boolean equals(T type) methods with @multimethod and Eq will delegate to the most specific one, defaulting to this == obj if there are no applicable methods?

In this case, I would argue that Eq has altered the default behaviour from Object because it is possible for different instances of Eq to claim they are equal but have different hash codes, which violates the assumptions made by any class that relies on consistent behaviour of equals and hashCode, for instance storing instances in a HashSet.

I agree in principle that not all things that are equal need to be hashable, but if you are overriding a method that has a contract set out by the language specification, I would expect that contract to be preserved.

You have understood Eq and multi method very well, Eq does indeed allow a
subclass to implement a more specific and type safe equality check which
would change the behaviour but if the subclass does nothing then the
behaviour is the standard object reference equality.

In effect the onus of responsibility moves to subclasses.

There is nothing in the language spec that requires hashcode to be
overridden when overriding equals. The closest is in the Java doc and I
quote:

Equals method:

"Note that it is generally necessary to override the hashCode method
whenever this method is overridden, so as to maintain the general contract
for the hashCode method, which states that equal objects must have equal
hash codes."

Hashcode:

"If two objects are equal according to the equals(Object) method, then
calling the hashCode method on each of the two objects must produce the
same integer result."

As you can see this clear states that if you override hashcode you must
override equals but not the other way around.

As is generally understood in the OO community, the root Object having
methods was one of the worst mistakes ever made in the Java type hierarchy.
Object(or maybe a Nil root) should have zero methods, then there should be
an interface for equality (Eq) with equals and maybe a default method
notEqual and Hashable should extend Eq changing the weakly enforced Java
doc guidelines in compiler time checks. Hash maps could then enforce that
keys must be hashable much like Sorted maps require comparable things or a
comparator on construction. Then we would only need to add support for
compiler verified immutable objects and most of the problems people have
with keys would go away!

Anyway I digress...

On Fri, 19 Jun 2015 3:01 pm Liam Williams notifications@github.com wrote:

Can you explain how Eq doesn't change the default behaviour from Object?

I am having a bit of trouble following multi.methodOption.

Am I right in thinking that it is possible to annotate one or more boolean
equals(T type) methods with @multimethod and Eq will delegate to the most
specific one, defaulting to this == obj if there are no applicable
methods?

In this case, I would argue that Eq has altered the default behaviour from
Object because it is possible for different instances of Eq to claim they
are equal but have different hash codes, which violates the assumptions
made by any class that relies on consistent behaviour of equals and
hashCode, for instance storing instances in a HashSet.

I agree in principle that not all things that are equal need to be
hashable, but if you are overriding a method that has a contract set out by
the language specification, I would expect that contract to be preserved.


Reply to this email directly or view it on GitHub
#11 (comment).

Thanks for your explanation, I found it useful.

For some reason I had it stuck in my head that the language specification was more strict than what you just quoted.

As for your comments about the root Object having methods, do you know of a language that has a class hierachy closer to the design you described?

I believe the prototypical language Self follows this model but the main one is of course Haskell.

If this interests you should try and go to any talk by Philip Wadler about type systems. He is one of the designers of Haskell, worked with Odersky to add generics to Java 5 and will happly talk about these kind of problems.