<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>
<channel>
	<title>Comments on: Commons-Lang and the equals()/compareTo() Debacle</title>
	<atom:link href="http://enfranchisedmind.com/blog/2006/01/30/commons-lang-and-the-equalscompareto-debacle/feed/" rel="self" type="application/rss+xml" />
	<link>http://enfranchisedmind.com/blog/2006/01/30/commons-lang-and-the-equalscompareto-debacle/</link>
	<description>Robert Fischer and Brian Hurt on Punditry, Programming Languages, and Other Religious Issues</description>
	<pubDate>Fri, 21 Nov 2008 02:47:52 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.3</generator>
		<item>
		<title>By: The Cheap Sitcom Clip Scene Blog Post &#124; Enfranchised Mind</title>
		<link>http://enfranchisedmind.com/blog/2006/01/30/commons-lang-and-the-equalscompareto-debacle/#comment-33557</link>
		<dc:creator>The Cheap Sitcom Clip Scene Blog Post &#124; Enfranchised Mind</dc:creator>
		<pubDate>Tue, 15 Jul 2008 04:58:55 +0000</pubDate>
		<guid isPermaLink="false">http://enfranchisedmind.com/blog/?p=62#comment-33557</guid>
		<description>[...] &#8220;Like most traumatic realizations, I’ve been having trouble getting the fundamental equals/compareTo brokeness of Java out of my head.&#8221; (Commons-Lang and the Equals()/CompareTo() Debacle) [...]</description>
		<content:encoded><![CDATA[<p>[...] &#8220;Like most traumatic realizations, I’ve been having trouble getting the fundamental equals/compareTo brokeness of Java out of my head.&#8221; (Commons-Lang and the Equals()/CompareTo() Debacle) [...]</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Candide</title>
		<link>http://enfranchisedmind.com/blog/2006/01/30/commons-lang-and-the-equalscompareto-debacle/#comment-1348</link>
		<dc:creator>Candide</dc:creator>
		<pubDate>Fri, 12 Jan 2007 18:14:10 +0000</pubDate>
		<guid isPermaLink="false">http://enfranchisedmind.com/blog/?p=62#comment-1348</guid>
		<description>I actually thought of a solution for this in Ruby.  It's horrible and ugly, but it works.

Whenever you load a class that could be equal to other sibling classes, re-define the comparison function by wrapping the old comparison function in a new function definition that handles the sibling cases, and calls the old function for all other cases.

I told you it was horrible and ugly.</description>
		<content:encoded><![CDATA[<p>I actually thought of a solution for this in Ruby.  It&#8217;s horrible and ugly, but it works.</p>
<p>Whenever you load a class that could be equal to other sibling classes, re-define the comparison function by wrapping the old comparison function in a new function definition that handles the sibling cases, and calls the old function for all other cases.</p>
<p>I told you it was horrible and ugly.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: bhurt-aw</title>
		<link>http://enfranchisedmind.com/blog/2006/01/30/commons-lang-and-the-equalscompareto-debacle/#comment-78</link>
		<dc:creator>bhurt-aw</dc:creator>
		<pubDate>Tue, 31 Jan 2006 16:09:13 +0000</pubDate>
		<guid isPermaLink="false">http://enfranchisedmind.com/blog/?p=62#comment-78</guid>
		<description>The worst-case problem is when you have a base class, and two different derived classes, and you want to compare the two different derived classes.  Even ignoring problems of the two different derived classes being in different packages, and wanting to compare private or package visible members, we still have a hard problem.

I think that, at the end of the day, comparison can not be a member function.  Certainly in closed languages like Java, C++, and Ocaml, where the entire implementation of the class has to be present when initially declared, the information needed to write a comparison class simply isn't available when you're writting any given class.  Note that both derived classes need to know about the other derived class, because you can't tell if equals will be called as derived1.compareTo(derived2), or derived2.compareTo(derived1).

But even in open languages like Ruby and Smalltalk, which allow you to add member functions to a class later, I still don't think compare can be a member function, because you need too much flexibility.  Say we have a base class and three derived classes, and want to have three different data structures- one holding derived classes one and two, one holding derived classes one and three, and one holding derived classes two and three.  Now you need three different comparison routines, each copied into two different classes!</description>
		<content:encoded><![CDATA[<p>The worst-case problem is when you have a base class, and two different derived classes, and you want to compare the two different derived classes.  Even ignoring problems of the two different derived classes being in different packages, and wanting to compare private or package visible members, we still have a hard problem.</p>
<p>I think that, at the end of the day, comparison can not be a member function.  Certainly in closed languages like Java, C++, and Ocaml, where the entire implementation of the class has to be present when initially declared, the information needed to write a comparison class simply isn&#8217;t available when you&#8217;re writting any given class.  Note that both derived classes need to know about the other derived class, because you can&#8217;t tell if equals will be called as derived1.compareTo(derived2), or derived2.compareTo(derived1).</p>
<p>But even in open languages like Ruby and Smalltalk, which allow you to add member functions to a class later, I still don&#8217;t think compare can be a member function, because you need too much flexibility.  Say we have a base class and three derived classes, and want to have three different data structures- one holding derived classes one and two, one holding derived classes one and three, and one holding derived classes two and three.  Now you need three different comparison routines, each copied into two different classes!</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Candide</title>
		<link>http://enfranchisedmind.com/blog/2006/01/30/commons-lang-and-the-equalscompareto-debacle/#comment-70</link>
		<dc:creator>Candide</dc:creator>
		<pubDate>Mon, 30 Jan 2006 19:15:41 +0000</pubDate>
		<guid isPermaLink="false">http://enfranchisedmind.com/blog/?p=62#comment-70</guid>
		<description>Didn't see your second post.

Your original solution -- which has been (and will probably continue to be) my own default solution -- was what I was working with when I first encountered this problem.  It's the standard solution I've seen kicking around in Dietel/Deitel/whatever and other places.  I just looked into my "Java Cookbook", and it's the solution they model right there (p226).

The problem I encountered was simplified to the 2D/3D case.  That case illustrates the asymmetric return values that pop up even in a trivial case of polymorphism, resulting in arbitrary behavior by the Set class.

So far, my only conclusion has been that one should never try to use equals(Object) if the objects aren't of precisely the same class.  This means that you can't have Map keys or Set values made up of different classes, and being the same "abstract class" or implementation the same interface aren't good enough.</description>
		<content:encoded><![CDATA[<p>Didn&#8217;t see your second post.</p>
<p>Your original solution &#8212; which has been (and will probably continue to be) my own default solution &#8212; was what I was working with when I first encountered this problem.  It&#8217;s the standard solution I&#8217;ve seen kicking around in Dietel/Deitel/whatever and other places.  I just looked into my &#8220;Java Cookbook&#8221;, and it&#8217;s the solution they model right there (p226).</p>
<p>The problem I encountered was simplified to the 2D/3D case.  That case illustrates the asymmetric return values that pop up even in a trivial case of polymorphism, resulting in arbitrary behavior by the Set class.</p>
<p>So far, my only conclusion has been that one should never try to use equals(Object) if the objects aren&#8217;t of precisely the same class.  This means that you can&#8217;t have Map keys or Set values made up of different classes, and being the same &#8220;abstract class&#8221; or implementation the same interface aren&#8217;t good enough.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Candide</title>
		<link>http://enfranchisedmind.com/blog/2006/01/30/commons-lang-and-the-equalscompareto-debacle/#comment-69</link>
		<dc:creator>Candide</dc:creator>
		<pubDate>Mon, 30 Jan 2006 19:08:45 +0000</pubDate>
		<guid isPermaLink="false">http://enfranchisedmind.com/blog/?p=62#comment-69</guid>
		<description>Actually, it's not that ridiculous at all.  Your question should return false naturally -- any Orange and the number 5 are different.  Beyond which, Java requires you to handle such a situation sensically because .  But consider different implementations of the Number class, or different implementations of the Map.Entry interface -- it's natural that I might want to collect a Set or Map of them.  If I do that, however, I need their equals(Object) method to work, because there's no way to provide a Comparator to most Set implementations -- and even the ones that do could drop to using equals(Object) without warning.

The fundamental problem is that it makes no sense for "equals" to be defined as an instance method, because implicit to the question of "equals" is "equals in terms of what"?

Again, consider the 2D and 3D point example, which is literally a textbook example of polymorphism and reuse -- the 2D point, however, will hapilly return "true" if it is asked if it is equal to the 3D point.  The 3D point, being aware of more state, will return "false" if it asked if it is equal to the 2D point.  This example trivially shows that one of the fundamental guarantees requried of the equals(Object) method -- that a.equals(b) == b.equals(a) is true -- cannot be defined in a simple way when polymorphism is in effect.  You need to use the EqualsBuilder.reflectionEquals(this, that) style of coding, but then you're carrying forward those issues we saw before.

And you still don't have a good case where two classes both implement an abstract base class or interface.  For instance, it would be reasonable to see code where you have maps of maps (any Perl-turned-Java programmer has written thos code).  If you accept abritrary maps, however, it's very possible that the a.equals(b) == b.equals(a) requirement could b violated given different implementations of a and b -- for one thing, any Map relying on EqualsBuilder would fail when presented with a non-related implementation of Map.

All of which throws the problem back into the user's lap.

The fundamental problem isn't that nonsensical things are being compared -- it's that whether two things are "sensical" for being compared is an abstract phrase.  The problem is that Java isn't functional enough to realize that it needs to be able to define "Equals in terms of..." for basically any data structure.

s/equals/compare to/g for another fun argument.</description>
		<content:encoded><![CDATA[<p>Actually, it&#8217;s not that ridiculous at all.  Your question should return false naturally &#8212; any Orange and the number 5 are different.  Beyond which, Java requires you to handle such a situation sensically because .  But consider different implementations of the Number class, or different implementations of the Map.Entry interface &#8212; it&#8217;s natural that I might want to collect a Set or Map of them.  If I do that, however, I need their equals(Object) method to work, because there&#8217;s no way to provide a Comparator to most Set implementations &#8212; and even the ones that do could drop to using equals(Object) without warning.</p>
<p>The fundamental problem is that it makes no sense for &#8220;equals&#8221; to be defined as an instance method, because implicit to the question of &#8220;equals&#8221; is &#8220;equals in terms of what&#8221;?</p>
<p>Again, consider the 2D and 3D point example, which is literally a textbook example of polymorphism and reuse &#8212; the 2D point, however, will hapilly return &#8220;true&#8221; if it is asked if it is equal to the 3D point.  The 3D point, being aware of more state, will return &#8220;false&#8221; if it asked if it is equal to the 2D point.  This example trivially shows that one of the fundamental guarantees requried of the equals(Object) method &#8212; that a.equals(b) == b.equals(a) is true &#8212; cannot be defined in a simple way when polymorphism is in effect.  You need to use the EqualsBuilder.reflectionEquals(this, that) style of coding, but then you&#8217;re carrying forward those issues we saw before.</p>
<p>And you still don&#8217;t have a good case where two classes both implement an abstract base class or interface.  For instance, it would be reasonable to see code where you have maps of maps (any Perl-turned-Java programmer has written thos code).  If you accept abritrary maps, however, it&#8217;s very possible that the a.equals(b) == b.equals(a) requirement could b violated given different implementations of a and b &#8212; for one thing, any Map relying on EqualsBuilder would fail when presented with a non-related implementation of Map.</p>
<p>All of which throws the problem back into the user&#8217;s lap.</p>
<p>The fundamental problem isn&#8217;t that nonsensical things are being compared &#8212; it&#8217;s that whether two things are &#8220;sensical&#8221; for being compared is an abstract phrase.  The problem is that Java isn&#8217;t functional enough to realize that it needs to be able to define &#8220;Equals in terms of&#8230;&#8221; for basically any data structure.</p>
<p>s/equals/compare to/g for another fun argument.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: TheHawk</title>
		<link>http://enfranchisedmind.com/blog/2006/01/30/commons-lang-and-the-equalscompareto-debacle/#comment-67</link>
		<dc:creator>TheHawk</dc:creator>
		<pubDate>Mon, 30 Jan 2006 19:01:17 +0000</pubDate>
		<guid isPermaLink="false">http://enfranchisedmind.com/blog/?p=62#comment-67</guid>
		<description>I think my "standard" default solution is to have the equals try to cast the other object into its own class and compare then. If it can't, merely return false. Actually, I'd extend the "cast" portion of that past merely the casting itself and also use reflection on the other object to try and see if the other object has a method to turns itself into an object of the other type. I think this should work for "most" situations, although you can still run into situations where you lose the reflexiveness. The problem is your dealing with multiple frames of comparison, and two objects that are equla in one, may not be equal in the other. I.E. 2 is equal to 2.343 as Integers, but not as Floats. Admittedly, in these situations to "cast" up or down you are either losing information or making stuff up which is whats skewing the equality.</description>
		<content:encoded><![CDATA[<p>I think my &#8220;standard&#8221; default solution is to have the equals try to cast the other object into its own class and compare then. If it can&#8217;t, merely return false. Actually, I&#8217;d extend the &#8220;cast&#8221; portion of that past merely the casting itself and also use reflection on the other object to try and see if the other object has a method to turns itself into an object of the other type. I think this should work for &#8220;most&#8221; situations, although you can still run into situations where you lose the reflexiveness. The problem is your dealing with multiple frames of comparison, and two objects that are equla in one, may not be equal in the other. I.E. 2 is equal to 2.343 as Integers, but not as Floats. Admittedly, in these situations to &#8220;cast&#8221; up or down you are either losing information or making stuff up which is whats skewing the equality.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: TheHawk</title>
		<link>http://enfranchisedmind.com/blog/2006/01/30/commons-lang-and-the-equalscompareto-debacle/#comment-66</link>
		<dc:creator>TheHawk</dc:creator>
		<pubDate>Mon, 30 Jan 2006 18:51:16 +0000</pubDate>
		<guid isPermaLink="false">http://enfranchisedmind.com/blog/?p=62#comment-66</guid>
		<description>I think the fundamental problem with the whole equals/compareTo mess is that it trys to handle everything. You end up having to handle a number of relatively nonsensical situations which in most cases will never come up. How many times are you actually going to hit the situation where you're asking "Is this Orange equal to the number 5?" CompareTo is even worse for nonsensical arrangements. In reality, any object really only has a certain set of other objects where comparison makes sense. Unfortunately, there's no good way to implement this, especially because that set can change without the objects knowledge.</description>
		<content:encoded><![CDATA[<p>I think the fundamental problem with the whole equals/compareTo mess is that it trys to handle everything. You end up having to handle a number of relatively nonsensical situations which in most cases will never come up. How many times are you actually going to hit the situation where you&#8217;re asking &#8220;Is this Orange equal to the number 5?&#8221; CompareTo is even worse for nonsensical arrangements. In reality, any object really only has a certain set of other objects where comparison makes sense. Unfortunately, there&#8217;s no good way to implement this, especially because that set can change without the objects knowledge.</p>
]]></content:encoded>
	</item>
</channel>
</rss>
