How to Write an Equality Method in Java (2009)
Two-place equality methods are a general solution, but not a very good idea. I have hit upon the a better abstraction for handling custom equality, which I call &quot;equality substitution&quot;. An objects equality method doesn&#x27;t perform the equality comparison, but rather nominates an alternative value which is used as that object&#x27;s representative for equality comparisons. That alternative is the &quot;equality substitute&quot;.<p>This is documented in the TXR Lisp reference manual: <a href="https:&#x2F;&#x2F;www.nongnu.org&#x2F;txr&#x2F;txr-manpage.html#N-02CDB347" rel="nofollow">https:&#x2F;&#x2F;www.nongnu.org&#x2F;txr&#x2F;txr-manpage.html#N-02CDB347</a><p>The key idea is that we have a reasonably rich set of built-in objects in the language that support <i>equal</i> equality useful ways.<p>Instead of trying to bend other objects to also support <i>equal</i> equality from scratch, we require objects to calculate a representative of themselves which is some language built-in data type that natively supports <i>equal</i>.<p>Equality substitution, though not a perfect concept, removes much of the error proneness of defining equality.<p>- The application developer is never required to write a hashing function. Not only does that relieve the application programmer of burden, but it also relieves the system of the burden of having to support custom hashing functions everywhere such as in hash tables.<p>- Inequality comes for free also. For instance, suppose a <i>user-account</i> structure has an equality method that produces the user-id (a character string) as the substitute. This means that we can now compare two <i>user-account</i> objects using <i>less</i>. One user-account is less than another if their respective <i>user-id</i> fields are <i>less</i>, which is a lexicographic comparison.<p>- The equality substitute can be the result of a complex calculation, which is cached in the object. I.e. the equal method can produce some compound key the first time it is invoked, and then use the cached value subsequently.<p>Demo:<p><pre><code>  This is the TXR Lisp interactive listener of TXR 257.
  Quit with :quit or Ctrl-D on an empty line. Ctrl-X ? for cheatsheet.
  Join TXR Rewards now, and get 15000 closing parentheses you can use anywhere.
  1&gt; (defstruct account ()
       user-id
       (:method equal (me) me.user-id))
  #&lt;struct-type account&gt;
  2&gt; (defvarl a (new account user-id &quot;aardvark&quot;))
  a
  3&gt; (defvarl b (new account user-id &quot;bat&quot;))
  b
  4&gt; (defvarl z (new account user-id &quot;zebra&quot;))
  z
  5&gt; (less a b z)
  t
  6&gt; (less b a)
  nil
  7&gt; (equal a b)
  nil
  8&gt; (equal a a)
  t
  9&gt; (equal a (new account user-id &quot;aardvark&quot;))
  t
  10&gt; (hash-equal a)
  327970753
  11&gt; (hash-equal &quot;aardvark&quot;)
  327970753
  12&gt; (defvarl h (hash))
  h
  13&gt; (set [h a] 100)
  100
  14&gt; (set [h b] 200)
  200
  15&gt; 4
  4
  16&gt; (set [h z] 300)
  300
  17&gt; h
  #H(() (#S(account user-id &quot;bat&quot;) 200) (#S(account user-id &quot;aardvark&quot;) 100)
   (#S(account user-id &quot;zebra&quot;) 300))
  18&gt; [h a]
  100
  19&gt; [h b]
  200
  20&gt; [h &quot;aardvark&quot;]
  100
</code></pre>
A key observation here is that the object a, of <i>account</i> type, is <i>equal</i> to the character string &quot;aardvark&quot;, as well as to any object of any type which produces that string as its equality substitute.<p>However, this is a very clear aspect of the model, and not a hidden pitfall.<p>We are saying that a participates in equality as if it literally were the string &quot;aardvark&quot; (though not satisfying the <i>stringp</i> predicate). 
This is clear from the beginning and you program your logic accordingly, taking advantage of that while anticipating whatever risks it may cause.<p>The system is very easy to understand and use; so far in every program where I took advantage of equality substitution, it was a pleasure to work with.