Equality in Java

I will put here a number of remarks about using equals in java. Until then, I will be content with a few examples.

Bitten by equals

Equals and inheritance play dirty tricks. I have recently met a problem in my hieroglyphic processor with this.

For printing purposes, I need to use CMYK colors. On printers, a "CMYK" black is quite different from a RGB Black. In fact, there is no one on one mapping between the two spaces, and usually, sending a RGB black to a printer is a bad idea in professional publishing.

Back to equals:

In my PDF generation code, I have the following function:

@Override
public void fill(Shape s) {
    if (! delegate.getColor().equals(getColor()))
        delegate.setColor(getColor());
    delegate.fill(getTransform().createTransformedShape(s));
}

delegate is a graphical object. The idea of the code is to change the delegate color if the current color for the delegate is different from the current color in this object, and then, to fill a shape.

Now, usually, the delegate starts with a drawing color which is a RGB black. When I draw, my color is a CMYK RBG. CMYK Color extends Color.

The problem is that equals is defined in the java Color class as follows:

public boolean equals(Object obj) {
    return obj instanceof Color && ((Color)obj).getRGB() == this.getRGB();
}

So, two colors are considered the same if they render the same in RGB. Note that this is properly documented in the Javadoc for Color.equals. But it's not the right thing to do for CMYK vs RGB... the behaviour of those are very different on printers.

Now, the question is: when you have a hierarchy, may it be reasonnable to consider two objects as equals, even if they don't ?

I think it's not a good idea in general, except when you have a very sound and implementation independant definition of equality. For colors, for instance, the given definition is indeed in line with the rest of the Color interface, but it misses the points that two corresponding colors in different colorspaces are merely images of one another, and not the same concept.

For Sets, for instance, the equals method is based on the mathematical definition of sets. A = B iff (A ⊂ B ⋀ B ⊂ A), so a HashSet and a TreeSet with the same contents are equals.

I might lead to surprise if someone is trying to compare two sorted sets with different ordering (which is quite an unusual case), but one can argue that, in this case, if one is interested in the ordering, he is comparing lists and not sets. So the ground is quite firm here.

To summarize, in this precise case, I added a comparison of the classes themselves to fix my equality.