Wednesday, July 03, 2013

Equals : Java inheritance abstraction leak


if(youKnowJavaCoding) 
startReading();
else 
break;


There is a java class Point2D.
int x, y;
Point2D defines equals which says if x values and y values are equal for two classes, then they are equal.
This is how it happens in the java world.

public void boolean equals(Object obj) {
if(!(obj instanceof Point2D)) {
return false;
else 
return this.x == obj.getX() && this.y== obj.getY();
}
}

Another class Point3D extends Point2D.
It can live upto the name but decides to do a different way.

public void boolean equals(Object obj) {
if(!(obj instanceof Point3D)) {
return false;
else 
return super.equals(obj) && this.z == obj.get(Z);
}
}
 
This breaks symmetry
Point2D says (1,2) is equal to (1,2,3)
Point3D says "No".

We tell Point3D to be the dragon warrior (or the man of steel) and find his parents.

public void boolean equals(Object obj) {
if(!(obj instanceof Point2D)) {
return false;
else if(!(obj instanceof Point3D)) {
return false;
else 
return super.equals(obj) && this.z == obj.getZ();
}
}

obj.getZ() doesn't work for Point2D.
Point3D still doesn't think (1,2,0) is equal to (1,2)

We cannot rely on simply letting super class handle the comparison, correct? 

Programmer(fuming) : Let the hell break loose, all Point3Ds are Point2Ds. Simply return super.equals(obj) , for all Point3Ds also. Sounds great! 

But, wait!

(1,2) equals (1,2, 1) and (1,2,-1). Aren't we being rude to transitivity here, honey?  

We can have another method in Point3D which says canEqual(Object obj) or few if clauses in the equals method which say if your z is 0, you can compare the Point2D and Point3D. Don't even think about it otherwise!

We have to sometimes come out of the abstraction to see the solution. 

No comments: