Jekyll2022-10-06T16:35:39-07:00https://jonathan.com/feed.xmlJonathan CastelloThe website & blog of Jonathan Castello.Jonathan Castellotwisol@jonathan.comWhat is object identity, and why should I care?2021-10-31T00:00:00-07:002021-10-31T00:00:00-07:00https://jonathan.com/2021/10/31/-object-identity<p>Academically, an <strong>object</strong> is the combination of three fundamental concepts into one atomic unit:</p>
<ul>
<li><strong>Behavior</strong> is the way in which an object interacts with its environment.</li>
<li><strong>State</strong> is the memory an object retains of prior interactions.</li>
<li><strong>Identity</strong> is what distinguishes one object from another, even when they’re identical under any other measure.</li>
</ul>
<p>If you’re familiar with an object-oriented language, chances are you could easily identify what features of the language correspond with “behavior” and “state”. In Java, for instance, you model “behavior” using methods, and you model “state” using fields<sup id="fnref:public-fields" role="doc-noteref"><a href="#fn:public-fields" class="footnote" rel="footnote">1</a></sup>. But “identity” is a bit of an odd concept in this lineup: it’s a bit less clear where “identity” comes into play. At worst, its existence can seem like a technicality or a useless piece of trivia.</p>
<p>My goal in this article is not only to explain how <strong>object identity</strong> manifests in Java (and just how deeply it’s embedded in object-oriented thinking), but to show how you can willfully leverage identity to achieve better software designs. With luck, a better understanding of identity will serve you well in functional languages, where – despite not being provided as a language primitive – it plays just as essential a role.</p>
<h2 id="looking-for-identity">Looking for identity</h2>
<p>Rather than conjuring up a prescriptive explanation for object identity and asking you to take it on faith, let’s consider an example program, and ask ourselves where identity plays a role.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Counter</span> <span class="o">{</span>
<span class="c1">// state</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="c1">// behavior</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">increment</span><span class="o">()</span> <span class="o">{</span> <span class="k">this</span><span class="o">.</span><span class="na">count</span> <span class="o">+=</span> <span class="mi">1</span><span class="o">;</span> <span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">getCount</span><span class="o">()</span> <span class="o">{</span> <span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">count</span><span class="o">;</span> <span class="o">}</span>
<span class="o">}</span>
<span class="kd">class</span> <span class="nc">Main</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">var</span> <span class="n">c1</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Counter</span><span class="o">();</span>
<span class="kt">var</span> <span class="n">c2</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Counter</span><span class="o">();</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">c1</span><span class="o">.</span><span class="na">getCount</span><span class="o">());</span> <span class="c1">//=> 0</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">c2</span><span class="o">.</span><span class="na">getCount</span><span class="o">());</span> <span class="c1">//=> 0</span>
<span class="n">c1</span><span class="o">.</span><span class="na">increment</span><span class="o">();</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">c1</span><span class="o">.</span><span class="na">getCount</span><span class="o">());</span> <span class="c1">//=> 1</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">c2</span><span class="o">.</span><span class="na">getCount</span><span class="o">());</span> <span class="c1">//=> 0</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>In this program, what draws your eye as being related to identity? Certainly, immediately after construction, <code class="language-plaintext highlighter-rouge">c1</code> and <code class="language-plaintext highlighter-rouge">c2</code> have the same state. They also have the same behavior: we can post a query to both counters and get the same answer. And, undoubtedly, if we continued performing the same interactions in parallel with these objects, they would continue to agree in every way<sup id="fnref:behavioral-equivalence" role="doc-noteref"><a href="#fn:behavioral-equivalence" class="footnote" rel="footnote">2</a></sup>. But we <em>don’t</em> – we next increment one counter, but not the other, and their subsequent answers diverge.</p>
<p>There are two keywords you might be eyeing at this point: <code class="language-plaintext highlighter-rouge">this</code> and <code class="language-plaintext highlighter-rouge">new</code>. It’s via <code class="language-plaintext highlighter-rouge">new</code> that objects get created in the first place, after all, and it’s via <code class="language-plaintext highlighter-rouge">this</code> that an object’s methods access and update its state. And you’d be right to eye these two keywords… but we can dig much deeper.</p>
<h2 id="removing-this">Removing <code class="language-plaintext highlighter-rouge">this</code></h2>
<p>Let’s start by looking at the <code class="language-plaintext highlighter-rouge">this</code> keyword. Yes, <code class="language-plaintext highlighter-rouge">this</code> allows our object’s behaviors to depend on its state, but we can actually do without it. We can <em>transform</em> our program into one that doesn’t use <code class="language-plaintext highlighter-rouge">this</code> – let’s see where we end up. (Remember that we’re <em>not</em> necessarily making this code any better – we’re only doing this to learn what makes objects tick.)</p>
<p>If we can’t get access to <code class="language-plaintext highlighter-rouge">count</code> via the <code class="language-plaintext highlighter-rouge">this</code> keyword, we have to get at it <em>somehow</em>. We’ll pass an instance of <code class="language-plaintext highlighter-rouge">Counter</code> in, instead.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Counter</span> <span class="o">{</span>
<span class="c1">// state</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="c1">// behavior</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">increment</span><span class="o">(</span><span class="nc">Counter</span> <span class="n">self</span><span class="o">)</span> <span class="o">{</span> <span class="n">self</span><span class="o">.</span><span class="na">count</span> <span class="o">+=</span> <span class="mi">1</span><span class="o">;</span> <span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">getCount</span><span class="o">(</span><span class="nc">Counter</span> <span class="n">self</span><span class="o">)</span> <span class="o">{</span> <span class="k">return</span> <span class="n">self</span><span class="o">.</span><span class="na">count</span><span class="o">;</span> <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Now there’s no <code class="language-plaintext highlighter-rouge">this</code> at all, but we’ve lost some fidelity in modeling: we have to reference the same object twice in <code class="language-plaintext highlighter-rouge">c1.increment(c1)</code>, and nothing prevents us from mixing and matching objects. Let’s make these methods static, for the time being.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Counter</span> <span class="o">{</span>
<span class="c1">// state</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="c1">// behavior</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">increment</span><span class="o">(</span><span class="nc">Counter</span> <span class="n">state</span><span class="o">)</span> <span class="o">{</span> <span class="n">state</span><span class="o">.</span><span class="na">count</span> <span class="o">+=</span> <span class="mi">1</span><span class="o">;</span> <span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">getCount</span><span class="o">(</span><span class="nc">Counter</span> <span class="n">state</span><span class="o">)</span> <span class="o">{</span> <span class="k">return</span> <span class="n">state</span><span class="o">.</span><span class="na">count</span><span class="o">;</span> <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>That’s a bit better, but also a bit worse: we now invoke <code class="language-plaintext highlighter-rouge">Counter.increment(c1)</code>, but we’ve lost dynamic dispatch. It didn’t matter much in this case, but if somebody had subclassed<sup id="fnref:subclassing-bad" role="doc-noteref"><a href="#fn:subclassing-bad" class="footnote" rel="footnote">3</a></sup> <code class="language-plaintext highlighter-rouge">Counter</code> and overridden its methods, <em>their</em> methods would have been called before, but now <em>our</em> static methods always get called.</p>
<p>I like to think of <code class="language-plaintext highlighter-rouge">static</code> items as being part of an implicit singleton object. Let’s extract that singleton into a real class:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Counter</span> <span class="o">{</span>
<span class="c1">// state</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="c1">// behavior</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">Trait</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">increment</span><span class="o">(</span><span class="nc">Counter</span> <span class="n">state</span><span class="o">)</span> <span class="o">{</span> <span class="n">state</span><span class="o">.</span><span class="na">count</span> <span class="o">+=</span> <span class="mi">1</span><span class="o">;</span> <span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">getCount</span><span class="o">(</span><span class="nc">Counter</span> <span class="n">state</span><span class="o">)</span> <span class="o">{</span> <span class="k">return</span> <span class="n">state</span><span class="o">.</span><span class="na">count</span><span class="o">;</span> <span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">class</span> <span class="nc">Main</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">var</span> <span class="n">trait</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Counter</span><span class="o">.</span><span class="na">Trait</span><span class="o">();</span>
<span class="kt">var</span> <span class="n">c1</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Counter</span><span class="o">();</span>
<span class="kt">var</span> <span class="n">c2</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Counter</span><span class="o">();</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">trait</span><span class="o">.</span><span class="na">getCount</span><span class="o">(</span><span class="n">c1</span><span class="o">));</span> <span class="c1">//=> 0</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">trait</span><span class="o">.</span><span class="na">getCount</span><span class="o">(</span><span class="n">c2</span><span class="o">));</span> <span class="c1">//=> 0</span>
<span class="n">trait</span><span class="o">.</span><span class="na">increment</span><span class="o">(</span><span class="n">c1</span><span class="o">);</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">trait</span><span class="o">.</span><span class="na">getCount</span><span class="o">(</span><span class="n">c1</span><span class="o">));</span> <span class="c1">//=> 1</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">trait</span><span class="o">.</span><span class="na">getCount</span><span class="o">(</span><span class="n">c2</span><span class="o">));</span> <span class="c1">//=> 0</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Now it’s possible to subclass both <code class="language-plaintext highlighter-rouge">Counter</code> and <code class="language-plaintext highlighter-rouge">Trait</code>; our methods are no longer <code class="language-plaintext highlighter-rouge">static</code>, so method calls will be dynamically dispatched to whatever concrete <code class="language-plaintext highlighter-rouge">Trait</code> has been implemented for a <code class="language-plaintext highlighter-rouge">Counter</code> subclass.</p>
<p>Since we can always transform our Java classes to avoid <code class="language-plaintext highlighter-rouge">this</code>, it can’t be essential to object identity. At best, we’ve encoded it using <em>other</em> forms of identity, and at worst it had nothing to do with identity at all. (I could go either way, but I think it’s telling that all we really did was provide the object as an explicit argument.)</p>
<h2 id="mutation-without-new">Mutation without <code class="language-plaintext highlighter-rouge">new</code></h2>
<p>Something rather interesting happened with our cleanups after removing <code class="language-plaintext highlighter-rouge">this</code>: our object’s state and behavior have been separated cleanly into two classes. Since identity is a part of every object, both the <code class="language-plaintext highlighter-rouge">Trait</code> instance and our original <code class="language-plaintext highlighter-rouge">Counter</code> instances must have identity. But we’re reusing our trait instance across <em>both</em> counters; in principle we could reuse a singleton <code class="language-plaintext highlighter-rouge">Trait</code> across <em>all</em> counters. It’s hard to claim, perhaps, that a singleton with no state of its own really <em>needs</em> identity.</p>
<p>This points to one of the roadblocks to understanding identity in Java: <em>everything</em> has it, in exactly the same way. It’s an invisible part of the fabric of every program, whether or not you actually make use of it. Worse, we sometimes have to work <em>against</em> identity – if you’ve ever made <a href="https://www.informit.com/articles/article.aspx?p=31551&seqNum=2">defensive copies</a>, this is why.</p>
<p>But more to our point, identity supports <strong>mutation</strong>. Objects with no state (or immutable state) may not need identity (<em>but we’ll get to that</em>), but identity is a <em>requirement</em> for objects with mutable state. To make the point, let’s rewrite our original<sup id="fnref:immutability-with-traits" role="doc-noteref"><a href="#fn:immutability-with-traits" class="footnote" rel="footnote">4</a></sup> program to use mutation as absolutely little as possible.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Records are new in Java 16!</span>
<span class="n">record</span> <span class="nf">Counter</span><span class="o">(</span><span class="kt">int</span> <span class="n">count</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">public</span> <span class="nf">Counter</span><span class="o">()</span> <span class="o">{</span> <span class="k">this</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span> <span class="o">}</span>
<span class="kd">public</span> <span class="nc">Counter</span> <span class="nf">increment</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">Counter</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">count</span> <span class="o">+</span> <span class="mi">1</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getCount</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">count</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">class</span> <span class="nc">Main</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">var</span> <span class="n">c1</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Counter</span><span class="o">();</span>
<span class="kt">var</span> <span class="n">c2</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Counter</span><span class="o">();</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">c1</span><span class="o">.</span><span class="na">getCount</span><span class="o">());</span> <span class="c1">//=> 0</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">c2</span><span class="o">.</span><span class="na">getCount</span><span class="o">());</span> <span class="c1">//=> 0</span>
<span class="n">c1</span> <span class="o">=</span> <span class="n">c1</span><span class="o">.</span><span class="na">increment</span><span class="o">();</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">c1</span><span class="o">.</span><span class="na">getCount</span><span class="o">());</span> <span class="c1">//=> 1</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">c2</span><span class="o">.</span><span class="na">getCount</span><span class="o">());</span> <span class="c1">//=> 0</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>We were a little too successful, actually. You’ll notice that <em>nowhere</em> is an object itself actually being mutated, and yet we can still make <code class="language-plaintext highlighter-rouge">c1.getCount()</code> return a different value. This tells us something very interesting about identity: it’s not <em>only</em> objects that have it! We can sneak mutation into the system through mutable local variables. Even though our counter objects do <em>have</em> identity, just as with our trait from before, it’s hard to argue that they actually <em>need</em> identity.</p>
<p>Moreover, while traits are a less common style in Java (though they exist; see <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Comparator.html">Comparator</a>), records and other [value-based types][value-based type] are common, and in fact are <a href="http://www.javapractices.com/topic/TopicAction.do?Id=29">preferred wherever possible</a>. Far from being one of the essential attributes of objects, identity sometimes seems like a feature nobody wanted!</p>
<p>Nonetheless, local variables are <em>not</em> sufficient for mutation in general. Since they’re local, only the function body can even reference them, much less change them. And sometimes, very occasionally, you <em>do</em> want to be able to check if two variables refer to the same object. Since every object has identity, these capabilities are available in every class, and it becomes very tempting (and all too easy) to leverage identity and mutation when other solutions might be more suitable – which is a shame, because you can do some very nice things with identity when you apply it consciously!</p>
<h2 id="shared-mutability">Shared mutability</h2>
<p>We can solve the first problem with a new class, <code class="language-plaintext highlighter-rouge">Register</code>. In some sense, we’re just taking the things we can do with local variables – read them and write them – and making a class with those behaviors. We don’t need to be able to check if two <code class="language-plaintext highlighter-rouge">Register</code>s are the same object here, but we get it thanks to object identity anyway. (Again, note that we’re not doing this because it’s necessarily <em>a good idea</em>, but because we’re trying to take different angles on this whole identity thing.)</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">final</span> <span class="kd">class</span> <span class="nc">Register</span><span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="o">{</span>
<span class="kd">private</span> <span class="no">T</span> <span class="n">value</span><span class="o">;</span>
<span class="kd">public</span> <span class="nf">Register</span><span class="o">(</span><span class="no">T</span> <span class="n">initialValue</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">value</span> <span class="o">=</span> <span class="n">value</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">set</span><span class="o">(</span><span class="no">T</span> <span class="n">newValue</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">value</span> <span class="o">=</span> <span class="n">value</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="no">T</span> <span class="nf">get</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">value</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="c1">// ...Counter...</span>
<span class="kd">class</span> <span class="nc">Main</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="kt">var</span> <span class="n">c1</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Register</span><span class="o"><>(</span><span class="k">new</span> <span class="nc">Counter</span><span class="o">());</span>
<span class="kd">final</span> <span class="kt">var</span> <span class="n">c2</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Register</span><span class="o"><>(</span><span class="k">new</span> <span class="nc">Counter</span><span class="o">());</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">c1</span><span class="o">.</span><span class="na">get</span><span class="o">().</span><span class="na">getCount</span><span class="o">());</span> <span class="c1">//=> 0</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">c2</span><span class="o">.</span><span class="na">get</span><span class="o">().</span><span class="na">getCount</span><span class="o">());</span> <span class="c1">//=> 0</span>
<span class="n">c1</span><span class="o">.</span><span class="na">set</span><span class="o">(</span><span class="n">c1</span><span class="o">.</span><span class="na">get</span><span class="o">().</span><span class="na">increment</span><span class="o">());</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">c1</span><span class="o">.</span><span class="na">get</span><span class="o">().</span><span class="na">getCount</span><span class="o">());</span> <span class="c1">//=> 1</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">c2</span><span class="o">.</span><span class="na">get</span><span class="o">().</span><span class="na">getCount</span><span class="o">());</span> <span class="c1">//=> 0</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The first nice thing about <code class="language-plaintext highlighter-rouge">Register</code> is how clearly it signals that mutation not only <em>can</em> happen, but that it’s <em>expected to</em> happen. In an environment where every object could potentially be mutable, and where complex object graphs mean interacting with one object could invisibly influence your interactions with another object, these kinds of signposts are invaluable to whichever developer is trying to understand what’s going on.</p>
<p>The second nice thing about <code class="language-plaintext highlighter-rouge">Register</code> is that it works for <em>any</em> type. We started with mutability that was specific to <code class="language-plaintext highlighter-rouge">Counter</code>, and in many ways we refactored the whole concept of shared mutability into a separate class altogether. I could wave my hands and mutter something about the SOLID principles here, but the point is that <code class="language-plaintext highlighter-rouge">Counter</code> is now <em>simpler</em> in a very real sense<sup id="fnref:deceptive-complexity" role="doc-noteref"><a href="#fn:deceptive-complexity" class="footnote" rel="footnote">5</a></sup>, and the concept of shared mutability is both centralized and reusable.</p>
<p>At this point, I hope it’s clear that without identity, we couldn’t have shared mutability. We could still have local mutability, but we can always replace a mutable local with a series of immutable locals (even if it can get <a href="https://www.cs.cmu.edu/~fp/courses/15411-f08/lectures/09-ssa.pdf">quite complex</a>), so local mutability is actually a pretty weak capability.</p>
<p>While shared mutability requires identity, we haven’t established that shared mutability is the <em>only</em> thing we can do with object identity. In fact, identity can be useful even in the absence of state <em>and</em> behavior.</p>
<h2 id="unforgeable-identity">Unforgeable identity</h2>
<p>In Java, object identity is stronger than local variable identity in two respects. First, only the immediate scope of the variable can access it; there is no way to give a called method access to that variable. Second, we cannot check if two variables are the same variable; it almost makes no sense to ask for such a thing! However, you can do <em>both</em> of these things with objects.</p>
<p>Since multiple methods can access the same object, we have shared mutability. But what can we do with the ability to check if two object references are the same? Is that even useful?</p>
<p>Yes. Yes it is.</p>
<p>First, identity-based equality is essential for writing a <a href="https://www.informit.com/articles/article.aspx?p=2861454&seqNum=8">type-keyed heterogeneous map</a>.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">final</span> <span class="kd">class</span> <span class="nc">TypeMap</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="nc">Map</span><span class="o"><</span><span class="nc">Class</span><span class="o"><?>,</span> <span class="nc">Object</span><span class="o">></span> <span class="n">map</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">HashMap</span><span class="o"><>();</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">put</span><span class="o">(</span><span class="nc">Object</span> <span class="n">value</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">map</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">value</span><span class="o">.</span><span class="na">getClass</span><span class="o">(),</span> <span class="n">value</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@SuppressWarnings</span><span class="o">(</span><span class="s">"unchecked"</span><span class="o">)</span>
<span class="kd">public</span> <span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="no">T</span> <span class="nf">get</span><span class="o">(</span><span class="nc">Class</span><span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="n">klass</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="o">(</span><span class="no">T</span><span class="o">)</span> <span class="k">this</span><span class="o">.</span><span class="na">map</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">klass</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">final</span> <span class="kd">class</span> <span class="nc">Main</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="kt">var</span> <span class="n">map</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">TypeMap</span><span class="o">();</span>
<span class="n">map</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">"Hello!"</span><span class="o">);</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">map</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="nc">String</span><span class="o">.</span><span class="na">class</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>It’s not obvious here, but <code class="language-plaintext highlighter-rouge">HashMap#get</code> will eventually invoke <code class="language-plaintext highlighter-rouge">equals()</code> to compare the given key with its stored key, and <code class="language-plaintext highlighter-rouge">Class#equals</code> uses reference equality. We can make things a <em>little</em> clearer by avoiding reflection altogether.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">final</span> <span class="kd">class</span> <span class="nc">TokenMap</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="nc">Map</span><span class="o"><</span><span class="nc">Token</span><span class="o"><?>,</span> <span class="nc">Object</span><span class="o">></span> <span class="n">map</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">HashMap</span><span class="o"><>();</span>
<span class="kd">public</span> <span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="kt">void</span> <span class="nf">put</span><span class="o">(</span><span class="nc">Token</span><span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="n">key</span><span class="o">,</span> <span class="no">T</span> <span class="n">value</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">map</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">key</span><span class="o">,</span> <span class="n">value</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@SuppressWarnings</span><span class="o">(</span><span class="s">"unchecked"</span><span class="o">)</span>
<span class="kd">public</span> <span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="no">T</span> <span class="nf">get</span><span class="o">(</span><span class="nc">Token</span><span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="n">key</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="o">(</span><span class="no">T</span><span class="o">)</span> <span class="k">this</span><span class="o">.</span><span class="na">map</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">key</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">Token</span><span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="o">{}</span>
<span class="o">}</span>
<span class="kd">final</span> <span class="kd">class</span> <span class="nc">Main</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="kt">var</span> <span class="n">map</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">TokenMap</span><span class="o">();</span>
<span class="kd">final</span> <span class="kt">var</span> <span class="n">key</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">TokenMap</span><span class="o">.</span><span class="na">Token</span><span class="o"><</span><span class="nc">String</span><span class="o">>();</span>
<span class="n">map</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">key</span><span class="o">,</span> <span class="s">"Hello!"</span><span class="o">);</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">map</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">key</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>In this case, we’re no longer restricted to one value of any type. We can quite easily construct two <em>distinct</em> tokens with the <em>same</em> type parameter. Either way, the key type carries type information about any associated value, and we <em>recover</em> that type information by comparing the token to one that we stored before. When we compare the given <code class="language-plaintext highlighter-rouge">Token<T></code> with the stored <code class="language-plaintext highlighter-rouge">Token<?></code> and discover that they are equal, we <em>know</em><sup id="fnref:casts" role="doc-noteref"><a href="#fn:casts" class="footnote" rel="footnote">6</a></sup> that the wildcard is in fact <code class="language-plaintext highlighter-rouge">T</code>, and therefore the value we stored with that token also has type <code class="language-plaintext highlighter-rouge">T</code>.</p>
<p>Moreover, we can safely pass this map around to other parts of the code with full confidence that if they don’t have the <em>exact</em> key that we used here, there’s no way to access the value associated with that key. The <code class="language-plaintext highlighter-rouge">Token</code> type models an <strong>unforgeable token</strong>, also – especially in the object-oriented domain – known as an <a href="https://tutorial.ponylang.io/object-capabilities/object-capabilities.html"><strong>object capability</strong></a><sup id="fnref:capability-equality" role="doc-noteref"><a href="#fn:capability-equality" class="footnote" rel="footnote">7</a></sup>.</p>
<p>The <code class="language-plaintext highlighter-rouge">Token</code> type here has neither state nor behavior; we’re using it purely for its identity, and with nothing at all to do with mutation of its (nonexistent) contents.</p>
<h2 id="putting-it-back-together">Putting it back together</h2>
<p>I’d like to close with an example where we consciously use object identity, supporting both mutation in the presence of shared references and token-based access to data.</p>
<p>In this case, we have a process (the “producer”) that may produce events of different kinds (“topics”), and some processes (the “consumers”) that are interested in specific kinds of events. We won’t futz with actual parallelism, but the producer and consumers are logically concurrent tasks: as we add more events, the consumers should be able to make further progress.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">final</span> <span class="kd">class</span> <span class="nc">Topic</span><span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="o">{}</span>
<span class="kd">final</span> <span class="kd">class</span> <span class="nc">EventStream</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="nc">List</span><span class="o"><</span><span class="nc">Event</span><span class="o"><?>></span> <span class="n">events</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o"><>();</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">add</span><span class="o">(</span><span class="nc">Topic</span><span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="n">topic</span><span class="o">,</span> <span class="no">T</span> <span class="n">event</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">Objects</span><span class="o">.</span><span class="na">requireNotNull</span><span class="o">(</span><span class="n">topic</span><span class="o">);</span>
<span class="k">this</span><span class="o">.</span><span class="na">events</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="k">new</span> <span class="nc">Event</span><span class="o"><>(</span><span class="n">topic</span><span class="o">,</span> <span class="n">event</span><span class="o">));</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="nc">Iterator</span><span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="nf">events</span><span class="o">(</span><span class="nc">Topic</span><span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="n">topic</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nc">TopicIterator</span><span class="o"><>(</span><span class="n">topic</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">TopicIterator</span><span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="kd">implements</span> <span class="nc">Iterator</span><span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="nc">Topic</span><span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="n">topic</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="kd">private</span> <span class="nf">TopicIterator</span><span class="o">(</span><span class="nc">EventStream</span> <span class="n">stream</span><span class="o">,</span> <span class="nc">Topic</span><span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="n">topic</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">topic</span> <span class="o">=</span> <span class="n">topic</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">hasNext</span><span class="o">()</span> <span class="o">{</span>
<span class="k">while</span> <span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">index</span> <span class="o"><</span> <span class="nc">EventStream</span><span class="o">.</span><span class="na">this</span><span class="o">.</span><span class="na">events</span><span class="o">.</span><span class="na">size</span><span class="o">())</span> <span class="o">{</span>
<span class="kd">final</span> <span class="kt">var</span> <span class="n">value</span> <span class="o">=</span> <span class="nc">EventStream</span><span class="o">.</span><span class="na">this</span><span class="o">.</span><span class="na">events</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">index</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">value</span><span class="o">.</span><span class="na">topic</span> <span class="o">==</span> <span class="k">this</span><span class="o">.</span><span class="na">topic</span><span class="o">)</span> <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">index</span> <span class="o">+=</span> <span class="mi">1</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@SuppressWarnings</span><span class="o">(</span><span class="s">"unchecked"</span><span class="o">)</span>
<span class="kd">public</span> <span class="no">T</span> <span class="nf">next</span><span class="o">()</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">hasNext</span><span class="o">())</span> <span class="k">throw</span> <span class="k">new</span> <span class="nc">NoSuchElementException</span><span class="o">();</span>
<span class="k">return</span> <span class="o">(</span><span class="no">T</span><span class="o">)</span> <span class="nc">EventStream</span><span class="o">.</span><span class="na">this</span><span class="o">.</span><span class="na">events</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">index</span><span class="o">).</span><span class="na">value</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="n">record</span> <span class="nc">Event</span><span class="o"><</span><span class="no">T</span><span class="o">>(</span><span class="nc">Topic</span><span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="n">topic</span><span class="o">,</span> <span class="no">T</span> <span class="n">event</span><span class="o">)</span> <span class="o">{}</span>
<span class="o">}</span>
<span class="kd">final</span> <span class="kd">class</span> <span class="nc">Main</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="kt">var</span> <span class="n">stream</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">EventStream</span><span class="o">();</span>
<span class="kd">final</span> <span class="kt">var</span> <span class="n">topic1</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Topic</span><span class="o"><</span><span class="nc">String</span><span class="o">>();</span>
<span class="kd">final</span> <span class="kt">var</span> <span class="n">topic2</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Topic</span><span class="o"><</span><span class="nc">Integer</span><span class="o">>();</span>
<span class="n">stream</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">topic1</span><span class="o">,</span> <span class="s">"1"</span><span class="o">);</span>
<span class="n">stream</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">topic2</span><span class="o">,</span> <span class="mi">2</span><span class="o">);</span>
<span class="n">stream</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">topic1</span><span class="o">,</span> <span class="s">"3"</span><span class="o">);</span>
<span class="k">for</span> <span class="o">(</span><span class="kd">final</span> <span class="kt">var</span> <span class="n">event</span> <span class="o">:</span> <span class="n">stream</span><span class="o">.</span><span class="na">events</span><span class="o">(</span><span class="n">topic1</span><span class="o">))</span> <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">event</span><span class="o">);</span>
<span class="c1">//=> 1, 3</span>
<span class="k">for</span> <span class="o">(</span><span class="kd">final</span> <span class="kt">var</span> <span class="n">event</span> <span class="o">:</span> <span class="n">stream</span><span class="o">.</span><span class="na">events</span><span class="o">(</span><span class="n">topic2</span><span class="o">))</span> <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">event</span><span class="o">);</span>
<span class="c1">//=> 2</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Let’s dissect this a bit.</p>
<ul>
<li>
<p>An <code class="language-plaintext highlighter-rouge">EventStream</code> object isn’t directly mutable in its own right, but the <code class="language-plaintext highlighter-rouge">ArrayList</code> it holds a reference to certainly is. We can think of <code class="language-plaintext highlighter-rouge">ArrayList</code> much like the <code class="language-plaintext highlighter-rouge">Register</code> class from before: an encapsulation of some pattern of mutability. The <code class="language-plaintext highlighter-rouge">EventIterator</code> is also mutable, but this time it’s because it has to be to obey the standard <code class="language-plaintext highlighter-rouge">Iterator</code> interface.</p>
</li>
<li>
<p>A <code class="language-plaintext highlighter-rouge">Topic</code> is an unforgeable token granting access to events of a particular type. It carries no runtime state or behavior; it exist only to be distinguished from other <code class="language-plaintext highlighter-rouge">Topic</code>s. The <code class="language-plaintext highlighter-rouge">EventStream</code> packages each event with its associated <code class="language-plaintext highlighter-rouge">Topic</code>, and lets you filter events on that topic<sup id="fnref:equality-witnesses" role="doc-noteref"><a href="#fn:equality-witnesses" class="footnote" rel="footnote">8</a></sup>. while we use that same <code class="language-plaintext highlighter-rouge">Topic</code> to filter the top-level stream for events of interest.</p>
<p>We could have achieved a similar system by replacing <code class="language-plaintext highlighter-rouge">Topic</code> with, say, <code class="language-plaintext highlighter-rouge">int</code>, but <code class="language-plaintext highlighter-rouge">int</code>s can be forged, and they also carry no type information about events. Consumer code would have to explicitly cast for the event type they’re expecting, and there would be nothing preventing the producer from adding events of the wrong type.</p>
</li>
</ul>
<p>Now, what could this be useful for? By its nature, an <code class="language-plaintext highlighter-rouge">EventStream</code> is something you’ll probably be sharing between multiple components of your system. At the same time, you don’t necessarily want every component to be able to couple to any other component<sup id="fnref:microservices" role="doc-noteref"><a href="#fn:microservices" class="footnote" rel="footnote">9</a></sup> – it becomes pretty hard to understand the flow of data through your system otherwise.</p>
<p>With this design, you can configure each component with the topics it should use, and it can <em>only</em> access those topics – the <code class="language-plaintext highlighter-rouge">EventStream</code> API makes it impossible to interact with any other topics. There’s no discoverability, and each topic is effectively its own little world; it just happens that, behind the scenes, all topics are conveniently collected and ordered in one place.</p>
<p>It’s not always what you want – but sometimes it’s <em>exactly</em> what you want. It’s really useful to have this kind of modeling tool in your toolbox!</p>
<hr />
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:public-fields" role="doc-endnote">
<p>There’s some subtlety here, as interacting with a public field can be considered a kind of “behavior” supported by the object. I would argue that it’s the “public” half of “public field” that’s doing the heavy lifting.</p>
<p>When you access a public field, you’re still interacting with the object in a way that depends on its identity and state; the fact that the interaction “looks” different doesn’t change the fact that it’s an interaction.</p>
<p>If this bothers you, you’re not alone: the <a href="http://wiki.c2.com/?UniformAccessPrinciple">Uniform Access Principle</a> suggests that all interactions should have a consistent syntax. Different software environments make different attempts on this ideal, either making methods more like fields or fields more like methods. Java developers often disallow field-like interactions altogether, instead providing the same behavior with explicit getters and setters. <a href="#fnref:public-fields" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:behavioral-equivalence" role="doc-endnote">
<p>This idea is called <a href="https://smallcultfollowing.com/babysteps/blog/2016/10/02/observational-equivalence-and-unsafe-code/">observational equivalence</a>, and is a great source of test cases. If you can define an object in both an “obvious but inefficient” way and a “complex but efficient” way, you can transfer confidence from the obvious way to the complex way by writing <a href="https://www.hillelwayne.com/hypothesis-oracles/">property tests</a> showing that they behave equivalently in context.</p>
<p>I especially like to do this for algorithms with both iterative and recursive forms, where the recursive form is often “obviously correct” but could potentially blow the stack. <a href="#fnref:behavioral-equivalence" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:subclassing-bad" role="doc-endnote">
<p>I’m leaving <code class="language-plaintext highlighter-rouge">final</code> off everywhere to make a point, but in a real codebase, I’d be marking all classes as <code class="language-plaintext highlighter-rouge">final</code> by default. <em>Most</em> classes are not designed for subclassing, and in general I want to clearly document the contract between a base class and its subclasses. <a href="#fnref:subclassing-bad" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:immutability-with-traits" role="doc-endnote">
<p>We can do this with our trait-style approach as well, and there are even some benefits that way, but traits may already be an unfamiliar-enough design mode that I don’t want it to drown out the rest of the discussion. Maybe for another blog post. <a href="#fnref:immutability-with-traits" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:deceptive-complexity" role="doc-endnote">
<p>This isn’t the time or the place, but one of my biggest pet peeves is when something appears simple <em>but isn’t</em>. Deceptive simplicity lulls you into a false sense of confidence, until something unexpected happens and you’re frantically <a href="https://www.jakeworth.com/examine-your-assumptions/">looking for the faulty assumption</a>. I want my mental model to be as accurate as possible to the reality of the code; any deviations are, in my opinion, simply bugs waiting to happen.</p>
<p>The original <code class="language-plaintext highlighter-rouge">Counter</code> is quite compact; before records were added in Java 17, the immutable version would have required <em>adding</em> <code class="language-plaintext highlighter-rouge">final</code> in order to <em>remove</em> mutation. Similarly for <code class="language-plaintext highlighter-rouge">static</code> inner classes, <code class="language-plaintext highlighter-rouge">final</code> classes, … <a href="#fnref:deceptive-complexity" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:casts" role="doc-endnote">
<p>Assuming nobody casts it to a different type parameter. But that’s like casting a <code class="language-plaintext highlighter-rouge">List<Integer></code> to a <code class="language-plaintext highlighter-rouge">List<String></code> – why would you do that? You’re just going to shoot yourself in the foot! (Ultimately, via a <code class="language-plaintext highlighter-rouge">ClassCastException</code>.)</p>
<p>There are some useful reasons to perform this kind of casting. <code class="language-plaintext highlighter-rouge">Optional.empty()</code> is a good example; internally it casts a statically allocated empty instance to whichever type was requested, since its behavior is the same no matter what type it’s instantiated with. But this trick works precisely because Optional is a <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/doc-files/ValueBased.html">value-based type</a>: it pretends it has no true identity of its own, so it’s not suitable for use as a token. <a href="#fnref:casts" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:capability-equality" role="doc-endnote">
<p>The question of whether capabilities <em>must</em> support equality comparison is rather interesting, The website for the E language has <a href="http://www.erights.org/elib/equality/grant-matcher/index.html">a good example</a> of where equality is important. <a href="#fnref:capability-equality" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:equality-witnesses" role="doc-endnote">
<p>In some functional languages, it’s not even necessary to perform a cast to assert that the unknown type variable is equal to some known type. <a href="https://wiki.haskell.org/GADTs_for_dummies">GADTs</a> are one way to do this, though I’m not sure they’d be sufficient for what we’re doing with topics and events. I think <a href="https://wiki.haskell.org/GADTs_for_dummies">Agda</a>, as a dependently-typed language, may be expressive enough to capture such principles.</p>
<p>In any case, Java <em>isn’t</em> expressive enough to do this for us. As long as we’re confident in the principle of inference at hand, and tightly scope it so it’s reasonably verifiable by manual inspection, we can leverage the same idea. It’s not unlike using an <code class="language-plaintext highlighter-rouge">unsafe</code> block in Rust. <a href="#fnref:equality-witnesses" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:microservices" role="doc-endnote">
<p>Unless you have a microservices architecture.</p>
<p>You probably don’t need a microservices architecture. If you need microservices, you’ll know. <a href="#fnref:microservices" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>Jonathan Castellotwisol@jonathan.comAcademically, an object is the combination of three fundamental concepts into one atomic unit: