Correct implementation of equals
Let say, you have class Point that have 2 coordinates. You want to define equals() method. It would be something like this:
class Point{
privateint x;
privateint y;
public Point(int x,int y){
this.x = x;
this.y = y;
publicboolean equals(Object o){
if (!(oinstanceof Point))
returnfalse;
Point p = (Point)o;
return x == p.x && y == p.y;
}
}
If this class is final, this works perfectly. But what if you want to extend this class and add new field (new data-member). Let's say ColorPoint, that have additional Color field. How you can overloaded equals() method in order to maintain equals() contract? (Solution, that stays replace inscanceof with getClass() will do the job, but with a great cost, Principe of Substiion will be violated).
I've seen recently one interesting solution here http://www.ddj.com/dept/java/184405053 I will explain it below.
Let's try to write naive implementation of ColorPoint:
class ColorPointextends Point{
private Color c;
public ColorPoint(int x,int y, Color c){
super(x, y);
this.c = c;
}
publicboolean equals(Object o){
if (!(oinstanceof ColorPoint))
returnfalse;
ColorPoint cp = (ColorPoint)o;
return super.equals(cp) && c == cp.c;
}
}
What's wrong with this approach? It is not symmetric. To introduce the problem let's write:
Point p=new Point(1,3);
ColorPoint cp=new ColorPoint(1,3, Color.BLACK);
System.out.println(p.equals(cp));//write true
System.out.println(cp.equals(p));//write false, because p is not instanceof ColorPoint
The problem is that Object o in equals() method has to be in the "right" type. If one want to decide programmatically that ColorPoint can't be equal to any Point, then the "right" type for Point is Poin.class, and the "right" type for ColorPoint is ColorPoint. If one want to decide that ColorPoint can be equal to Point if the Color of ColorPoint is black (that is he is looking to all Points as ColorPoint with "default" value, from his perspective all Points are black). Then the "right" type will very. For the Point class it has to be Point.class and for ColorPoint class, if it's color is black , the "right" type is Point.class, otherwise it is ColorPoint.class. Below is listing of the Solution.
This is a case, when ColorPoint should not be equal to any Point:
class Point{
privateint x;
privateint y;
public Point(int x,int y){
this.x = x;
this.y = y;
}
[b]protected Object getEquivalenceClass(){
return Point.class;
}[/b]
publicboolean equals(Object o){
if (!(oinstanceof Point))
returnfalse;
Point p = (Point)o;
return [b]getEquivalenceClass().equals(p.getEquivalenceClass())[/b]
&& x == p.x && y == p.y;
}
}
class ColorPointextends Point{
private Color c;
public ColorPoint(int x,int y, Color c){
super(x, y);
this.c = c;
}
[b]protected Object getEquivalenceClass(){
return ColorPoint.class;
}[/b]
publicboolean equals(Object o){
if (!(oinstanceof ColorPoint))
returnfalse;
ColorPoint cp = (ColorPoint)o;
return super.equals(cp) && c == cp.c;
}
}
In case no new fields are added (i.e. its equivalence class is equal), simply:
class AnotherPointextends Point{
public AnotherPoint(int x,int y){
super(x, y);
}
}
In case Point is black ColorPoint. The equals() of ColorPoint should also relaxed a bit.
class Point{
privateint x;
privateint y;
public Point(int x,int y){
this.x = x;
this.y = y;
}
[b]protected Object getEquivalenceClass(){
return Point.class;
}[/b]
publicboolean equals(Object o){
if (!(oinstanceof Point))
returnfalse;
Point p = (Point)o;
return [b]getEquivalenceClass().equals(p.getEquivalenceClass())[/b]
&& x == p.x && y == p.y;
}
}
class ColorPointextends Point{
private Color c;
public ColorPoint(int x,int y, Color c){
super(x, y);
this.c = c;
}
[b]protected Object getEquivalenceClass(){
return Color.black.equals(c) ? Point.class : ColorPoint.class;
}[/b]
[b]publicboolean equals(Object o){
if (oinstanceof ColorPoint){
ColorPoint cp = (ColorPoint)o;
if (c != cp.c)
returnfalse;
}
return super.equals(o);
}
[/b]
}
Note: 1. getEquivalenceClass() can return java.lang.Class and the test can become getEquivalenceClass() == p.getEquivalenceClass().
2. On the contrary additional enum can be defined and return as getEquivalenceClass() does.
Does this is correct?
[9772 byte] By [
alexsmaila] at [2007-11-27 11:48:15]

No, it's silly and needlessly complicated by the look of it.
Points please [holds out hand]
In general, there is no way to correctly implement the equals() contract to work in a class hierarchy, because of the symmetric requirement: if x.equals(y) == true then y.equals(x) == true as well.
Now you can make your ColorPoint take into account its superclass, but in general you won't be able to make Point take into account all of its subclasses, breaking symmetry.
So the o instanceof Point test isn't really good enough. It should be o.getClass().equals(this.getClass()).
Read the Object API for the exact requirements.
I should write some clarification notes.
1. I know contract of the Object.equals() method.
2. I know that by using getClass() besides instanceof equals() method can be implemented without violation of Object.equals() contract. The disadvantage of the getClass approachis that it violates the "Substitution Principle," which states that a method expecting a superclass instance must behave properly when presented with a subclass instance. If a subclass
adds a few new methods, or trivially modifies behavior (e.g., by emitting a trace upon each method invocation), programmers will be surprised when subclass and superclass instances don't interact properly. Objects that "ought to be equal" won't be, causing programs to fail or behave erratically. For example, AnotherPoint will be not equal to the Point.
3. I know, that with instanceof it is "impossible" to implement hierarchy of the object, when new field is added to the SubClass. But I never see the prove of this statement.
4. I found out interesting implementation with instanceof and with additional field in SubClass. Moreover, this implementation is flexible enough to enable the programm to decide whether SubClass is equal to the SuperClass in some cases or it has to be totally unequal.
See also next note.
Message was edited by:
alexsmail
See also bug_id=6479372.
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6479372
The principle used here in getEquivalenceClass(), that is method that return reference this is considered to be added to Java. In such a case the implementation, if it is correct one, will be significantly easier.
I don't know if this will help you but I read half of your post because I don't have a lot of time but I believe that the last one is incorrect and that cp.equals(p)
will always return false because p doesn't have a color....I maybe be out of point because I didn't read all your post but I hope I've helped you a little bit...
I tend to agree with you there, he seems to be trying to force the language to do something it's not meant to do. I've tried to do this before and eventually realised that what I was trying to do was not only impossible, but based upon faulty logic and nonsensical anyway. Why on Earth would you want to be able to compare a Point to a ColorPoint and say that they're equal? They're not equal, one's a Point, the other is a ColorPoint.
In the naive implementation indeedcp.equals(p)
will always return false. But in the final solution it is not the case. In this case while instanceof ColorPoint will return false, but equals() method is modified not to return false, but to delegate the execution to super.equals(). In this case, it will be Point class and true will be returned.
Your question helps to highlights change in equals() implementation, indeed.
P.S. If you don't have a lot of time, you should looked on the last code written in the first topic (after you have figured out what about the topic). Anyway, thank you for you time.
Read Joshua Bloch's "Effective Java". That will tell you how to implement equals properly.
There's no getting around the symmetry argument, though.
%
> Read Joshua Bloch's "Effective Java"
Sound advice. Regardless of whether you're writing an equals method or not :-)
In my application there is 2 objects represents different customer types. They have "is a" relationship (inheritance). But subClass has only one additional field, that has no influence on the behavior of subClass. It is used up to day for statistic exclusively. We see this subClass as superClass and we think it to be equal to its superClass if all, but this additional field is equal. It is real-world example.
In the sample, think about that you draw the points on the screen. Whether it is ColorPoint or Point this object has to have some color. It is reasonable to think that any point in the screen is black, until other is specified. If you are looking on it in such a way, it is reasonable to say that if ColorPoint has black color it could be compared to Point. Of course, if you think that this is nonsense, for example, Point represents "conception" to be a point, and not particular object in the screen, in such a case ColorPoint and Point is totally different and there is no reason to be equal. My point is, it should be up to the programmer to decide whether he wants to consider object with new field equal to the super or not. He should be able to implement comparasion in both cases.
> Read Joshua Bloch's "Effective Java". That will tell
> you how to implement equals properly.
>
> There's no getting around the symmetry argument,
> though.
>
> %
It is not totally correct. You can implement the equals() without single violation of the contract by using getClass(). See one of the first posting. Joshua Bloch know it, but this was not covered in the book.
> There's no getting around the symmetry argument,
> though.
Can you rigorously prove it or point me where can I found such a prove? Can you point me why my implementation is wrong? Where I break up the contract of equals() or make another breaking up? If the answer on the first question is negative I will be grateful to you if you will find problem in my implementation or if you prove that it is correct one.
> > Read Joshua Bloch's "Effective Java"
>
> Sound advice. Regardless of whether you're writing an
> equals method or not :-)
Thank you for your advise. It is great book. The problem is that it is state that if subClass has additional filled that should be taken in account in equals() method, there is no way to implement such relationship. First of all, there is no prove to this statement, second of all I found some way to do this, but I don't know whether it is correct. Again, Joshua Bloch's "Effective Java" states that if subClass have additional instance there is no way to implement correctly equals(). This statement is wrong (consider getClass() approach). So reading the book will not help in my case.
If you say "ColorPoint" extends "Point", as you write it implies 'They have "is a" relationship (inheritance).'
Then everything what is true for Point, is true for ColorPoint.
Now two Point's are considered equal if their coordinates are equal.
This does not hold true however for ColorPoints so ColorPoints are no Points!
Well, you can of course get a "correct" result in a tightly controlled hierarchy of a few classes.
However, if you have public class that other people can extend, you will not be able to maintain this.
If I extend your ColorPoint class and override equals the "traditional" way, your system breaks.
So, in the general sense you will not be able to do this in a reusable library. But you can do it in a limited/controlled environment. This will work in a technical sense. It doesn't work from a pure OO standpoint (the Liskov substitution principle comes to mind).
> In general, there is no way to correctly implement
> the equals() contract to work in a class hierarchy,
> because of the symmetric requirement: if x.equals(y)
> == true then y.equals(x) == true as well.
>
> Now you can make your ColorPoint take into account
> its superclass, but in general you won't be able to
> make Point take into account all of its subclasses,
> breaking symmetry.
>
> So the o instanceof Point test isn't really good
> enough. It should be
> o.getClass().equals(this.getClass()).
I disagree.
You can specify in the docs at some level of the class or interface hierarchy that subclasses must implement it such and such way, including that equals is true if both objects pass instanceof this base class/interface.
That's exactly what List, Map, and Set do.
Once you specify instanceof at level X, every subclass of X must use instanceof X.
Now, of course, you can't compile-time enforce a correct implementation, but then, you can't compile-time enforce a correct implementation of anything.
jverda at 2007-7-29 18:17:59 >

If there were arguent-based method dispatching in Java (or C++ etc) then it would solve this problem.
There are talks about introducing this into C++.
> It is not totally correct. You can implement the
> equals() without single violation of the contract by
> using getClass().
Only if you use getClass at every level in the hierarchy. Once you use instanceof, every class below that level must use instanceof TheSameClass, else symmetry will be broken.
jverda at 2007-7-29 18:17:59 >

> If there were arguent-based method dispatching in
> Java (or C++ etc) then it would solve this problem.
Which problem is that?
jverda at 2007-7-29 18:17:59 >

> Well, you can of course get a "correct" result in a
> tightly controlled hierarchy of a few classes.
>
> However, if you have public class that other people
> can extend, you will not be able to maintain this.
>
> If I extend your ColorPoint class and override equals
> the "traditional" way, your system breaks.
>
> So, in the general sense you will not be able to do
> this in a reusable library. But you can do it in a
> limited/controlled environment. This will work in a
> technical sense. It doesn't work from a pure OO
> standpoint (the Liskov substitution principle comes
> to mind).
So, technically it is correct implementation. That is good news.
Can you explain why it is wrong from a pure OO point of view? If Liskov substitution principle is breaks all of this doesn't worth anything. Can you write please or point to the existing example when Liskov substitution principle will be broken? Could you restrict my implementation, that Liskov substitution principle will not be broken? For example, if getEquivalenceClass() method is overridden it must return getClass().
If I have a problem with Liskov substitution principle that can be fixed, then this solution worth nothing.
Thank you in advance.
> So, technically it is correct implementation. That is
> good news.
Yes; it fulfills the contract of the equals method, but it shouldn't be forgotten that now you need to override the hashCode method to fulfill its contract.
> Can you explain why it is wrong from a pure OO point
> of view? If Liskov substitution principle is breaks
> all of this doesn't worth anything. Can you write
> please or point to the existing example when Liskov
> substitution principle will be broken?
The LSP basically says that if a statement holds for a type T, then the statement should should hold when you substitute T with its subtype S. http://en.wikipedia.org/wiki/Liskov_substitution_principle
Now, the statement "two Point objects are 'equal' when they have the same coordinates" holds, but the statement that LSP implies, that "two ColorPoint objects are 'equal' when they have the same coordinates," does not in this case. Therefore the principle is broken.
> If I have a problem with Liskov substitution
> principle that can be fixed, then this solution worth
> nothing.
>
Well, it's only a general principle, not a law. If by a slight breach of the LSP you obtain a significant benefit theres no reason to not do it.
> Why on Earth would you want to be
> able to compare a Point to a ColorPoint and say that
> they're equal? They're not equal, one's a Point, the
> other is a ColorPoint.
The fact that they're not the same class doesn't automatically mean it doesn't make sense for them to be equal. Without knowing the details of the domain here, it seems possible (though unlikely, IMHO) that the rule could be that two points are equal if they have the same coordinates, and that color doens't come into play.
jverda at 2007-7-29 18:17:59 >

> > Why on Earth would you want to be
> > able to compare a Point to a ColorPoint and say
> that
> > they're equal? They're not equal, one's a Point,
> the
> > other is a ColorPoint.
>
> The fact that they're not the same class doesn't
> automatically mean it doesn't make sense for them to
> be equal. Without knowing the details of the domain
> here, it seems possible (though unlikely, IMHO) that
> the rule could be that two points are equal if they
> have the same coordinates, and that color doens't
> come into play.
But the original code defined two ColorPoints to be equal if they have the
equal coordinates *and* equal colors.
If a Point could equal a ColorPoint, you're in trouble. For example
if Point(0,0) equals ColorPoint(0,0,Red), then
Point(0,0) equals ColorPoint(0,0,Green) and then
ColorPoint(0,0,Red) equals ColorPoint(0,0,Green), woops!
For an example of where an equals works that doesn't restrict itself
to one class, consider the definition of List's equals.
Two lists are equals if they have the same length and their ith elements are equal.
So an ArrayList could equal a LinkedList.
> But the original code defined two ColorPoints to be
> equal if they have the
> equal coordinates *and* equal colors.
Like I said: I don't know the details of this particular domain. (Translation: I didn't read the thread all that closely.) I was just talking about the general case.
> If a Point could equal a ColorPoint, you're in
> trouble. For example
> if Point(0,0) equals ColorPoint(0,0,Red), then
> Point(0,0) equals ColorPoint(0,0,Green) and then
> ColorPoint(0,0,Red) equals ColorPoint(0,0,Green),
> woops!
>
> For an example of where an equals works that doesn't
> restrict itself
> to one class, consider the definition of List's
> equals.
> Two lists are equals if they have the same length and
> their ith elements are equal.
> So an ArrayList could equal a LinkedList.
Right. This is what I was saying before. Both getClass and instanceof can be valid, depending on the semantics of the particular classes in question. But once you do instanceof, every subclass must do instanceof that same base class or interface.
jverda at 2007-7-29 18:17:59 >

> In my application there is 2 objects represents
> different customer types. They have "is a"
> relationship (inheritance). But subClass has only one
> additional field, that has no influence on the
> behavior of subClass. It is used up to day for
> statistic exclusively. We see this subClass as
> superClass and we think it to be equal to its
> superClass if all, but this additional field is
> equal. It is real-world example.
> In the sample, think about that you draw the points
> on the screen. Whether it is ColorPoint or Point this
> object has to have some color. It is reasonable to
> think that any point in the screen is black, until
> other is specified. If you are looking on it in such
> a way, it is reasonable to say that if ColorPoint has
> black color it could be compared to Point. Of course,
> if you think that this is nonsense, for example,
> Point represents "conception" to be a point, and not
> particular object in the screen, in such a case
> ColorPoint and Point is totally different and there
> is no reason to be equal. My point is, it should be
> up to the programmer to decide whether he wants to
> consider object with new field equal to the super or
> not. He should be able to implement comparasion in
> both cases.
Excellent rationalization for a wrong implementation.
If you want a method that implements the above functionality then add a method that does that.
Equals is not that method however.
Equals has a specific functional use in terms of the Java API and your solution at a minimum makes understanding that much harder and might simply break it.
Adding a different function doesn't break anything.
> Can you rigorously prove it or point me where
> can I found such a prove? Can you point me why my
> implementation is wrong? Where I break up the
> contract of equals() or make another breaking up? If
> the answer on the first question is negative I will
> be grateful to you if you will find problem in my
> implementation or if you prove that it is correct one.
Pointless.
The fact that I can write code that passes a unit test doesn't me that I am in fact meeting the architecutural/design goals of the system.
What if I re-write the Java API so that instead of it relying on assumptions about Equals in numerous places it instead uses a method called VeryEqual. That would allow you to write your method and it wouldn't break anything that exists. And it is certainly possible.
But I doubt that any one is going to claim that that it good or ideal solution.
> > Can you explain why it is wrong from a pure OO
> point
> > of view? If Liskov substitution principle is
> breaks
> > all of this doesn't worth anything. Can you write
> > please or point to the existing example when
> Liskov
> > substitution principle will be broken?
>
> The LSP basically says that if a statement holds for
> a type T, then the statement should should hold when
> you substitute T with its subtype S.
> http://en.wikipedia.org/wiki/Liskov_substitution_princ
> iple
>
> Now, the statement "two Point objects are 'equal'
> when they have the same coordinates" holds, but the
> statement that LSP implies, that "two ColorPoint
> objects are 'equal' when they have the same
> coordinates," does not in this case. Therefore the
> principle is broken.
>
First of all I know what is Liskov substitution principle. I even mention it in this topic (I call it substitution principle, though). Second, thank you for the link I saw the rigorous definition first time.
Back to ColorPoint. You have already agreed that you was mistaken in your interpretation of the 'equal' for ColorPoint.
> > Can you rigorously prove it or point me
> where
> > can I found such a prove? Can you point me why my
> > implementation is wrong? Where I break up the
> > contract of equals() or make another breaking up?
> If
> > the answer on the first question is negative I
> will
> > be grateful to you if you will find problem in my
> > implementation or if you prove that it is correct
> one.
>
> Pointless.
>
> The fact that I can write code that passes a unit
> test doesn't me that I am in fact meeting the
> architecutural/design goals of the system.
>
> What if I re-write the Java API so that instead of it
> relying on assumptions about Equals in numerous
> places it instead uses a method called VeryEqual.
> That would allow you to write your method and it
> wouldn't break anything that exists. And it is
> certainly possible.
>
> But I doubt that any one is going to claim that that
> it good or ideal solution.
You totally miss my point.
Theorem: Given existing Java API contracts (particularly contract of Object.equals()) and Java capability (particularly, impossible to use contravariant variable in overloading of Object.equals()) , It is impossible to override method Object.equals() that will be different from the Object's equals that makes shallow comparasion by object ids (==) and will fulfill both contract of Object.equals() and will not break OO principles (particularly, Liskov substitution principle).
I am talking about that nobody proofs that there is no nontrivial implementation of the equals() method that fulfill its contract and doesn't break OO principles.
Think about it. Let suppose, that there is no physical law that prohibits Perpetuum mobile and I am demonstrated it. So, you should consider my construction seriously. But if you know that there is a low that prohibits Perpetuum mobile you can say, "your construction is rubbish".
Peoples, that says, that my implementation is rubbish, because they believe that such construction is impossible are wrong. Untill, rigorous proof would exist, that prohibits such construction they should consider such implementation seriously.
Dude, you are not making any sense.
I don't know what proof you're looking for, but, as already pointed out, whether or not a particular equals implemenation violates LSP is irrelevant. It has absolutely nothing to do with whether it's a good or correct implementation.
jverda at 2007-7-29 18:17:59 >

> First of all I know what is Liskov substitution
> principle. I even mention it in this topic (I call it
> substitution principle, though). Second, thank you
> for the link I saw the rigorous definition first
> time.
A philosophical question: if you hadn't seen the definition of LSP before, how can you say that you "knew" what LSP was?
> Back to ColorPoint. You have already agreed that you
> was mistaken in your interpretation of the 'equal'
> for ColorPoint.
I hadn't posted in this thread before so I don't see where I had been mistaken or agreed to anything.
> If a Point could equal a ColorPoint, you're in
> trouble.
Not necesarily.
> if Point(0,0) equals ColorPoint(0,0,Red), then
> Point(0,0) equals ColorPoint(0,0,Green) and then
> ColorPoint(0,0,Red) equals ColorPoint(0,0,Green),
> woops!
>
In this case there is no "woops." Here Point(0,0) can equal to only ColorPoint(0,0,black), not to points of other colours. In other words, plain Points are identified with black ColorPoints only, not with points of other colours. It's easy to check that the requirements of the equals method are satisfied.
> Dude, you are not making any sense.
>
> I don't know what proof you're looking for, but, as
> already pointed out, whether or not a particular
> equals implemenation violates LSP is irrelevant. It
> has absolutely nothing to do with whether it's a good
> or correct implementation.
Well, from the formal point of view you are right. getClass() implementation is correct, in the sence that it fulfill the contract of Object.equals(). Moreover, there is semantic of such equal comparasion that sounds good. The question is, the price you pay to achieve this goal.
>
> You totally miss my point.
And you missed mine.
>
> I am talking about that nobody proofs that there is
> no nontrivial implementation of the equals() method
> that fulfill its contract and doesn't break OO
> principles.
Most people do not claim because that because it is theorectically possible to rob a bank that it therefor must be a good idea to do so.
Some people do.
I didn't claim that you couldn't implement the solution you want.
I didn't claim that it wouldn't be possible to create a correctly functioning application doing it that way.
I do however claim that it isn't a good idea.
Feel free to provide a proof that it is a good idea.
> Well, from the formal point of view you are right.
> getClass() implementation is correct, in the sence
> that it fulfill the contract of Object.equals().
Formal has nothing to do with it. In some cases getClass will be correct. In other cases instanceof will be correct. It depends on your requirements.
> Moreover, there is semantic of such equal comparasion
> that sounds good. The question is, the price you pay
> to achieve this goal.
What are you talking about? What price? If you need equality to be defined one way, use getClass. If you need it to be defined another way, use instanceof. It all depends on your requirements and the semantics of your classes.
jverda at 2007-7-29 18:18:04 >

> > First of all I know what is Liskov substitution
> > principle. I even mention it in this topic (I call
> it
> > substitution principle, though). Second, thank you
> > for the link I saw the rigorous definition first
> > time.
>
> A philosophical question: if you hadn't seen the
> definition of LSP before, how can you say that you
> "knew" what LSP was?
>
> > Back to ColorPoint. You have already agreed that
> you
> > was mistaken in your interpretation of the
> 'equal'
> for ColorPoint.
>
> I hadn't posted in this thread before so I don't see
> where I had been mistaken or agreed to anything.
I will write the answer to philosophical question first. I knew what is Liskov Substitution Principle without knowing formal definition. It was something like "Suppose, there is type Father and Son that extends from the Father. If in any point in the program where Father object is expecting, Son will be supplied, the program behaviour will not changed." It is good enough. I don't know what's your education, but almost any arbitrary chosen man will said that he knows what is Natural number. But if this man will be pointed out to the formal definition by Peano's axioms http://en.wikipedia.org/wiki/Natural_number#Peano_axioms he will be suprised. But Peano's axioms is off topic here.
As for the fact that the quoted post is you first post here, sorry, it is my confusion. Anyway, you could read above the answer (not mine) why your interpretation of the 'equal' is wrong. I hope I am not confused again, it is 3 o'clock at the night here and I want to sleep.
> I do however claim that it isn't a good idea.
>
> Feel free to provide a proof that it is a good idea.
Can you explain me, please, why it is not good idea? I really want to know.
> > Well, from the formal point of view you are right.
> > getClass() implementation is correct, in the sence
> > that it fulfill the contract of Object.equals().
>
> Formal has nothing to do with it. In some cases
> getClass will be correct. In other cases instanceof
> will be correct. It depends on your requirements.
>
>
>
> > Moreover, there is semantic of such equal
> comparasion
> > that sounds good. The question is, the price you
> pay
> > to achieve this goal.
>
> What are you talking about? What price? If you need
> equality to be defined one way, use getClass. If you
> need it to be defined another way, use instanceof.
> It all depends on your requirements and the
> semantics of your classes.
You forgot one simple thing. While you can design well you class hierarchy it should be flexible and extensible. I will talk only about extensibility. Somebody else, or even you, should be able to extend your hierarchy. He should do it by fulfilling contract of the Object.equals() and any more specific contract of the super-classes.
The original problem was, that if instanceof approach is using to expansible class, this class can't be extended if the subClass add additional field. If getClass() approach is used, then "trivial subClass" see AnotherPoin for example, can't defined with the semantic that this trivial subClass would be equal to superClass.
Message was edited by:
alexsmail
> > I do however claim that it isn't a good idea.
> >
> > Feel free to provide a proof that it is a good
> idea.
>
> Can you explain me, please, why it is not good idea?
> I really want to know.
See reply #24.
>
> You forgot one simple thing. While you can design
> well you class hierarchy it should be flexible and
> extensible.
Wrong.
The first goal is meeting the business requirements. Both the current ones and the known future ones.
The second goal is to strive towards an implementation that lends itself to lower cost maintainance.
Over engineering idealism will never meet the secondary goal and at least sometimes can lead to problems with the first if not outright failure.
> I will talk only about extensibility.
> Somebody else, or even you, should be able to extend
> your hierarchy. He should do it by fulfilling
> contract of the Object.equals() and any more specific
> contract of the super-classes.
Very few classes ever need to override Equals. And of those even less will have a parent child relationship (see below.)
> The original problem was, that if instanceof approach
> is using to expansible class, this class can't be
> extended if the subClass add additional field. If
> getClass() approach is used, then "trivial subClass"
> see AnotherPoin for example, can't defined with the
> semantic that this trivial subClass would be equal to
> superClass.
Most classes should neither be children not parents ever. Composition is prefered over inheritence.
> > What are you talking about? What price? If you
> need
> > equality to be defined one way, use getClass. If
> you
> > need it to be defined another way, use instanceof.
> > It all depends on your requirements and the
> > semantics of your classes.
>
> You forgot one simple thing.
No, I haven't.
> While you can design
> well you class hierarchy it should be flexible and
> extensible.
Not necessarily. In any case, neither form of equals hurts extensibilty or flexibility.
> I will talk only about extensibility.
> Somebody else, or even you, should be able to extend
> your hierarchy.
Maybe, maybe not. But it's irrelevant. In some hierarchies instanceof is appropriate. In others, getClass is appropriate.
> He should do it by fulfilling
> contract of the Object.equals() and any more specific
> contract of the super-classes.
Yes, of course. Still irrelevant.
> The original problem was, that if instanceof approach
> is using to expansible class, this class can't be
> extended if the subClass add additional field.
If the instanceof approach is used, it's because it was already decided that it's not appropriate to extend it with a subclass that has an additional field that is significant to equals. (Note that not all fields have to be used for equals. Again, it's up to the semantics of your classes, based on your requirements.)
So nothing is lost.
> If
> getClass() approach is used, then "trivial subClass"
> see AnotherPoin for example, can't defined with the
> semantic that this trivial subClass would be equal to
> superClass.
If getClass is used, it's because it was already decided that it wouldn't be a appropriate to have an instance of a subclass be equal to an instance of a superclass. That's why getClass would be chosen.
So, again, nothing is lost.
jverda at 2007-7-29 18:18:04 >

> As for the fact that the quoted post is you first
> post here, sorry, it is my confusion. Anyway, you
> could read above the answer (not mine) why your
> interpretation of the 'equal' is wrong.
Could you please explain that better? Which argument in which post shows my "interpretation" wrong?
> > > I do however claim that it isn't a good idea.
> > >
> > > Feel free to provide a proof that it is a good
> > idea.
> >
> > Can you explain me, please, why it is not good
> idea?
> > I really want to know.
>
> See reply #24.
Sorry, I missed that reply. It was last reply on the first page.
> > In my application there is 2 objects represents
> > different customer types. They have "is a"
> > relationship (inheritance). But subClass has only
> one
> > additional field, that has no influence on the
> > behavior of subClass...
> > In the sample, think about that you draw the
> points
> > on the screen. Whether it is ColorPoint or Point
> this
> > object has to have some color. It is reasonable to
> > think that any point in the screen is black, until
> > other is specified...
>
> Excellent rationalization for a wrong
> implementation.
>
> If you want a method that implements the above
> functionality then add a method that does that.
>
> Equals is not that method however.
>
> Equals has a specific functional use in terms of the
> Java API and your solution at a minimum makes
> understanding that much harder and might simply break
> it.
>
> Adding a different function doesn't break anything.
The semantic of the equal comparasion is left to the programmer. Contract of the Object.equals() say nothing about the semantic. It says exclusively about properties of such equals. I am not breaking any of such properties.
> >
> > You forgot one simple thing. While you can design
> > well you class hierarchy it should be flexible and
> > extensible.
>
> Wrong.
>
> The first goal is meeting the business requirements.
> Both the current ones and the known future ones.
>
> The second goal is to strive towards an
> implementation that lends itself to lower cost
> maintainance.
>
> Over engineering idealism will never meet the
> secondary goal and at least sometimes can lead to
> problems with the first if not outright failure.
It depends on how "deep" you writing the code. If you write J2EE container or class that will make audit in your application or another basic to your application functionality it is totally wrong. It depends on whether your not your code used as infrastructure or not. It is philosophical dispute in any case, so lets drop it.
> Very few classes ever need to override Equals. And
> of those even less will have a parent child
> relationship (see below.)
>
> Most classes should neither be children not parents
> ever. Composition is prefered over inheritence.
Here you described status de-facto. Indeed, for most classes Object.equals() shouldn't be overridden. Exception is DTO and JavaBeans. For example, different objects that represent different customer's types is served as DTO. There is hierarchy of such classes. In the case of DTO or JavaBeans why composition shoould be prefered over inheritance? See also my next reply.
> In some
> hierarchies instanceof is appropriate. In others,
> getClass is appropriate.
>
> If the instanceof approach is used, it's because it
> was already decided that it's not appropriate to
> extend it with a subclass that has an additional
> field that is significant to equals. (Note that not
> all fields have to be used for equals. Again, it's up
> to the semantics of your classes, based on your
> requirements.)
> If getClass is used, it's because it was already
> decided that it wouldn't be a appropriate to have an
> instance of a subclass be equal to an instance of a
> superclass. That's why getClass would be
> chosen.
>
> So, again, nothing is lost.
This is de-facto status with equals. I personally has 2 problem with this.
- you are limited the programmer to extend your hierarchy. You should add to the contract of your base class, that instanceof approach is used, so subClass with additional field that has to be taken into account shouldn't be added, or that getClass() approach is used, so "trivial subClass" shouldn't be added. It is too restrictive. And what if your requirement will be change in the future in such a way that you should add such "forbidden" class?
- what should you do in the case of Data-transfer-objects (DTO) or JavaBeans? Should you not to override Object.equals() method but define you own method as jschell advices?
> > As for the fact that the quoted post is you first
> > post here, sorry, it is my confusion. Anyway, you
> > could read above the answer (not mine) why your
> > interpretation of the 'equal' is wrong.
>
> Could you please explain that better? Which argument
> in which post shows my "interpretation" wrong?
See reply #22, and reply #30.
> - you are limited the programmer to extend your
> hierarchy. You should add to the contract of your
> base class, that instanceof approach is used, so
> subClass with additional field that has to be taken
> into account shouldn't be added, or that getClass()
> approach is used, so "trivial subClass" shouldn't be
> added.
Yes, you should document the behavior of equals. So what? You should document the behavior of all public methods. Nothing special about equals here.
> It is too restrictive.
What's too restrictive? In what way? Equals is too restrictive because you have to document it?
> And what if your
> requirement will be change in the future in such a
> way that you should add such "forbidden" class?
What of it? I guess you're saying nobody should ever write any software then, because requirements could change in a way that breaks your existing design. This isn't anything special to equals.
> - what should you do in the case of
> Data-transfer-objects (DTO) or JavaBeans? Should you
> not to override Object.equals() method but define you
> own method as jschell advices?
It depends on the situation, but I would generally override equals for DTOs and JavaBeans, as many tools, libraries, and frameworks expect equals to be overridden.
I really don't see your point. There are two valid approaches to equals. One is more appropriate in some cases, and the other in other cases. Neither one is perfectly, 100%, unbreakably flexible and extensible, but then, nothing else is either, nor should it be.
jverda at 2007-7-29 18:18:09 >

> > Could you please explain that better? Which argument
> > in which post shows my "interpretation" wrong?
>
> See reply #22, and reply #30.
In reply 30 I discuss the implementation that you propose, which fulfills the contract of the equals method. In reply 22 BDLH shows that the "nave" implementation doesn't fulfill the contract. I dont see where in those posts my "interpretation of 'equal'" is shown wrong, nor anything that opposes my view on that the implementation you propose breaches LSP.
> > - you are limited the programmer to extend your
> > hierarchy. You should add to the contract of your
> > base class, that instanceof approach is used, so
> > subClass with additional field that has to be
> taken
> > into account shouldn't be added, or that
> getClass()
> > approach is used, so "trivial subClass" shouldn't
> be
> > added.
>
> Yes, you should document the behavior of equals. So
> what? You should document the behavior of all public
> methods. Nothing special about equals here.
>
>
> > It is too restrictive.
>
> What's too restrictive? In what way? Equals is too
> restrictive because you have to document it?
Implementation details dictates you how you should write equal. It is nonsense. See also below.
> It depends on the situation, but I would generally
> override equals for DTOs and JavaBeans, as many
> tools, libraries, and frameworks expect equals to be
> overridden.
How can you do this? You can't use instanceof approach, because new essential fields are added. So you have to use getClass() approach which dictate you semantic that in the typical case is inappropriate to you. Besides, you're braking Liskov substitution principle in this case. Nearly all JavaBeans and DTOs hierarchies I have seen in practice is impossible to implement with getClass() approach.
> I really don't see your point. There are two valid
> approaches to equals. One is more appropriate in some
> cases, and the other in other cases. Neither one is
> perfectly, 100%, unbreakably flexible and extensible,
> but then, nothing else is either, nor should it be.
Lets examine JavaBeans and DTO exclusively. In this case instanceof approach is inappropriate (see above). getClass() approach in typical case is too restrictive.
I introduce you implementation that can be used in this case and you can decide does you want it to behave as getClass() approach or instanceof approach or even to mix them up. Of course, you should restrict contract of the equals, for example to point about getEquivalanceClass() method, appropriately. But you have to do it anyway.
> > > Could you please explain that better? Which
> argument
> > > in which post shows my "interpretation" wrong?
> >
> > See reply #22, and reply #30.
>
> In reply 30 I discuss the implementation that you
> propose, which fulfills the contract of the equals
> method. In reply 22 BDLH shows that the "nave"
> implementation doesn't fulfill the contract. I dont
> see where in those posts my "interpretation of
> 'equal'" is shown wrong, nor anything that opposes my
> view on that the implementation you propose breaches
> LSP.
Let's try from the scratch. Write down (again, sorry) your "interpretation" and I'll answer you.
> > > It is too restrictive.
> >
> > What's too restrictive? In what way? Equals is too
> > restrictive because you have to document it?
>
> mplementation details dictates you how you should
> write equal. It is nonsense. See also below.
This makes no sense. I have no idea what you're trying to say here.
> > It depends on the situation, but I would generally
> > override equals for DTOs and JavaBeans, as many
> > tools, libraries, and frameworks expect equals to
> be
> > overridden.
>
> ow can you do this? You can't use instanceof
> approach, because new essential fields are added.
Probably true in most cases, but so what?
> So
> you have to use getClass() approach
Okay, so we use getClass. So what?
> which dictate you
> semantic that in the typical case is inappropriate to
> you.
I have no idea what you're saying here.
> Besides, you're braking Liskov substitution
> principle in this case.
I don't think so. But even if we are, so what? As already stated, LSP is simply a guideline. It's not an inviolable truth handed down from the gods.
> Nearly all JavaBeans and
> DTOs hierarchies I have seen in practice is
> impossible to implement with getClass() approach.
Why?
> > ets examine JavaBeans and DTO exclusively. In this
> > case instanceof approach is inappropriate (see
> > above). getClass() approach in typical case is too
> > restrictive.
Why? What's too restrictive about it? What is too restrictive? You have not clarified what you view as too restrictive or why, at all.
Look when deciding if two things are equal, it's natural that part of the equality test be whether they're of the same type.
Now, "same type" could have multiple interpretations. The two that pop most readily to mind are "exactly the same class" and "descended from some particular base class or interface." These are expressed by getClass and instanceof, repsectively. There may be other valid interpretations, but in every case I've come across, one of these two has been appropriate.
Again: What. Point. Are. You. Trying. To. Make?
> I introduce you implementation that can be used in
> this case and you can decide does you want it to
> behave as getClass() approach or instanceof approach
> or even to mix them up. Of course, you should
> restrict contract of the equals, for example to point
> about getEquivalanceClass() method, appropriately.
> But you have to do it anyway.
WTF are you talking about?
jverda at 2007-7-29 18:18:09 >

> Let's try from the scratch. Write down (again, sorry)
> your "interpretation" and I'll answer you.
In reply 26 you claim that You have already agreed that you was mistaken in your interpretation of the 'equal' for ColorPoint. I reply by asking you to explain why you think that my interpretation is wrong and point out that it was my first post in this thread and that I couldn't possibly have already agreed to anything.
In your reply 34 you acknowledge this fact and advice me with Anyway, you could read above the answer (not mine) why your interpretation of the 'equal' is wrong. I reply by asking which post in particular you refer to.
According to your reply 44 you refer to the replies 22 and 30, neither of which seem to address your view on my "interpretation." Thus your claim in replies 26 and 34 still remains unjustified and unexplained. I believe it's not a good practice to assert that some idea is "wrong" without having a justification off-hand, so I offer you yet another possibility to explain yourself.
Sorry. I confused you with another person on this thread.
Can you write down your claim, so that I will be able to answer you? Perhaps, I am wrong. I can't found your initial post, that "have wrong interpretation". Can you repeat it, please?
alexsmail,
Is there a point to any of this? Or is this just going to be one of those threads that goes on for 400 posts with no resolution?
Because you had an idea. As everyone has told you by now it's a bad one. And as should also be obvious by now you can do whatever you feel you should or whatever you feel that you would like to do, etc.
Now you seem to be just engaging in debate and trying to defend your point in a very confused manner. You misquote people, you post indeciepherable and lengthy ramblings and the whole thing seems to be just sinking in a deeper morass. To be honest you are starting to resemble daFei.
At any rate, what is the resolution that you hope to achieve in this thread? Are you planning to change your mind? Or are you trying to convince everyone else that you are right?
If it's the former then please elucidate on what you exactly don't understand so that it can be explained to you. If it's the latter then please give this up. You aren't going to be convincing anyone here that you have a great and fundmental need to do whatever or that you have hit upon a great new idea of how to do it.
Because this is REALLY unpromising.
> I can't found
> your initial post, that "have wrong interpretation".
> Can you repeat it, please?
What in the ****?
You can't find a post that he didn't make and you would like him to repeat it? That makes no sense. At all. In any language.
jverd, I get your point.
I will try again to clarify myself once more. For JavaBeans and DTO instanceof approach in most cases is inappropriate. getClass() approach fails in Liskov substitution principle, but you're right, it is not tragedy. But it can be the case that semantic induced by this approach is inappropriate. Here is example.
public class Customer {
private String firstName;
private String lastName;
...
}
public class AdvancedCustomer extrends Customer{
private String linkShareSiteId;
...
}
In all places throughout the code where Customer is expected, AdvancedCustomer can be supplied (this behaviour should be kept). In addition, there is some method that expected to receive AdvancedCustomer , that is has specific to AdvancedCustomer functionality.
How do you want to implement equals() method ?
cotton.m I want to know why it is bad idea. It is technically right, there is problem in current instanceof and getClass() approach (yes, I agree, the problem arise only in few percentage of the classes, but still there is a problem). Why is it bad idea? You can see my example in previous post.
> Sorry. I confused you with another person on this
> thread.
Apology accepted, we all make mistakes.
> Can you write down your claim, so that I will be able
> to answer you? Perhaps, I am wrong. I can't found
> your initial post, that "have wrong interpretation".
> Can you repeat it, please?
Reply #20.
> How do you want to implement equals() method ?
That would depend on the requirements that you set, since you are the designer.
I would approach the problem from a different perspective: why do you need two classes in the first place? Do "AdvancedCustomer" objects behave differently from normal "Customers," or is the only difference between them that "AdvancedCustomers" hold more attributes? I smell misuse of inheritance here.