<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://blog.colinwilliams.name/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.colinwilliams.name/" rel="alternate" type="text/html" /><updated>2026-04-29T22:54:57+00:00</updated><id>https://blog.colinwilliams.name/feed.xml</id><title type="html">Technical Polyglot</title><subtitle>I love exploring new technology and honing my craft as a software engineer. I&apos;ve learned a broad range of languages, play around with hardware and do some light sysadmin work in my free time.</subtitle><entry><title type="html">Understanding Abstractions</title><link href="https://blog.colinwilliams.name/2026/04/29/understanding-abstractions.html" rel="alternate" type="text/html" title="Understanding Abstractions" /><published>2026-04-29T00:00:00+00:00</published><updated>2026-04-29T00:00:00+00:00</updated><id>https://blog.colinwilliams.name/2026/04/29/understanding-abstractions</id><content type="html" xml:base="https://blog.colinwilliams.name/2026/04/29/understanding-abstractions.html"><![CDATA[<p>A skill I often see underdeveloped in developers is layering simple
abstractions. Maintaining this discipline is crucial in dodging code
quagmires, which can be deadly when bugs occur. This has always been
important, but because genies don’t understand this concept
maintaining this quality is becoming central to the value we bring.</p>

<p>To illustrate this concept, I’m going to provide an example from a
recent project I’ve been working on. On a Go board, adjacent points in
same state are considered connected:</p>

<p><img src="/images/go-groups.png" alt="A 5x5 annotated Go board in this configuration: NNNNN/BBBN(4)N/WWB(1)NN/NWW(3)B(2)B/N(5)NWWB" width="250" /></p>

<p>So the groups marked 1, 2 and 3 are each distinct in this regard. I’m
also going to refer to 4 and 5 as connected groups, this is useful for
the logic I’m developing even though Go players don’t refer to them in
this way.</p>

<p>I want to develop a cache of these groups, which can be accessed
efficiently using a javascript <code class="language-plaintext highlighter-rouge">Map</code>. As new stones are added and
removed from the board, this will need to be updated accordingly.</p>

<h1 id="smaller-is-better">Smaller is Better</h1>

<p>A point on the board is comprised of x and y coordinates, which feels
natural to represent as <code class="language-plaintext highlighter-rouge">[x, y]</code>. It’s tempting to also the state of
that position, but this is the first lesson: the more sprawling the
abstraction the harder it is to reason about it.</p>

<p>To illustrate this point, let me share with you a simple utility
function I use in several places in this project:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">neighbors</span><span class="p">([</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">]:</span> <span class="nx">Point</span><span class="p">):</span> <span class="nx">Point</span><span class="p">[]</span> <span class="p">{</span>
  <span class="k">return</span> <span class="p">[[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">]]</span>
    <span class="p">.</span><span class="nx">map</span><span class="p">(([</span><span class="nx">ox</span><span class="p">,</span> <span class="nx">oy</span><span class="p">])</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="nx">x</span> <span class="o">+</span> <span class="nx">ox</span><span class="p">,</span> <span class="nx">y</span> <span class="o">+</span> <span class="nx">oy</span><span class="p">])</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Because it doesn’t need to be aware of the state of the board, it can
remain self contained and more generic. If it needs the state, how do
we figure out what to include there? One option would be to put some
sort of dummy value:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">neighbors</span><span class="p">([</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">,</span> <span class="nx">_</span><span class="p">]:</span> <span class="nx">Point</span><span class="p">):</span> <span class="nx">Point</span><span class="p">[]</span> <span class="p">{</span>
  <span class="k">return</span> <span class="p">[[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">]]</span>
    <span class="p">.</span><span class="nx">map</span><span class="p">(([</span><span class="nx">ox</span><span class="p">,</span> <span class="nx">oy</span><span class="p">])</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="nx">x</span> <span class="o">+</span> <span class="nx">ox</span><span class="p">,</span> <span class="nx">y</span> <span class="o">+</span> <span class="nx">oy</span><span class="p">,</span> <span class="dl">"</span><span class="s2"> </span><span class="dl">"</span><span class="p">])</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This would be functional, but adds unnecessary weight to the
abstraction. Now, whenever you use the results of this function, you
have to keep in mind that the state of that point should be
disregarded. Eventually, you’ll accidentally use that state and have
a confusing bug to track down when it leaks into other parts of the
code.</p>

<p>The other option is to provide enough context to provide meaningful
state:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">neighbors</span><span class="p">([</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">]:</span> <span class="nx">Point</span><span class="p">,</span> <span class="nx">board</span><span class="p">:</span> <span class="nx">Board</span><span class="p">):</span> <span class="nx">Point</span><span class="p">[]</span> <span class="p">{</span>
  <span class="k">return</span> <span class="p">[[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">]]</span>
    <span class="p">.</span><span class="nx">map</span><span class="p">(([</span><span class="nx">ox</span><span class="p">,</span> <span class="nx">oy</span><span class="p">])</span> <span class="o">=&gt;</span> <span class="p">{</span>
      <span class="kd">const</span> <span class="nx">nx</span> <span class="o">=</span> <span class="nx">x</span> <span class="o">+</span> <span class="nx">ox</span>
      <span class="kd">const</span> <span class="nx">ny</span> <span class="o">=</span> <span class="nx">x</span> <span class="o">+</span> <span class="nx">oy</span>
      <span class="k">return</span> <span class="p">[</span><span class="nx">nx</span><span class="p">,</span> <span class="nx">ny</span><span class="p">,</span> <span class="nx">board</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">nx</span><span class="p">,</span> <span class="nx">ny</span><span class="p">)]</span>
    <span class="p">})</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Again, this would be functional, but introduces different
problems. To start, when writing the tests for this function, a
<code class="language-plaintext highlighter-rouge">Board</code> has to be constructed to provide this state. Next, knowledge
of the state is helpful in some situations but can become a burden in
others, which I’ll come back to when I discuss sets of points.</p>

<h1 id="grouping-reduces-complexity">Grouping Reduces Complexity</h1>

<p>Discussing the entire <code class="language-plaintext highlighter-rouge">Board</code> class is beyond the scope of this
article, but notice that because <code class="language-plaintext highlighter-rouge">Point</code> doesn’t include state we can
have a signature like this: <code class="language-plaintext highlighter-rouge">get(point: Point): State | undefined</code>. In the
previous example, because state was part of the type, we had to call a
version that looked like this: <code class="language-plaintext highlighter-rouge">get(x: number, y: number): State | undefined</code>.</p>

<p>To understand the consequence of this, consider the situation where
you only want neighbors that are valid board positions:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nx">Board</span> <span class="p">{</span>
  <span class="p">...</span>
  <span class="nx">neighbors</span><span class="p">(</span><span class="nx">point</span><span class="p">:</span> <span class="nx">Point</span><span class="p">):</span> <span class="nx">Point</span><span class="p">[]</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">neighbors</span><span class="p">(</span><span class="nx">point</span><span class="p">).</span><span class="nx">filter</span><span class="p">((</span><span class="nx">n</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="k">this</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">n</span><span class="p">))</span>
  <span class="p">}</span>
  <span class="p">...</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Notice that this function doesn’t need to understand anything about
how <code class="language-plaintext highlighter-rouge">Point</code> is structured. If it was aware of state, then to call
<code class="language-plaintext highlighter-rouge">get</code> we would have to break into the individual x and y
coordinates. Moreover, it ceases to make sense to decompose the work
into two simple functions.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nx">Board</span> <span class="p">{</span>
  <span class="p">...</span>
  <span class="nx">neighbors</span><span class="p">([</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">,</span> <span class="nx">_</span><span class="p">]:</span> <span class="nx">Point</span><span class="p">):</span> <span class="nx">Point</span><span class="p">[]</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">[[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">]]</span>
      <span class="p">.</span><span class="nx">map</span><span class="p">(([</span><span class="nx">ox</span><span class="p">,</span> <span class="nx">oy</span><span class="p">])</span> <span class="o">=&gt;</span> <span class="nx">board</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">x</span> <span class="o">+</span> <span class="nx">ox</span><span class="p">,</span> <span class="nx">y</span> <span class="o">+</span> <span class="nx">oy</span><span class="p">))</span>
      <span class="p">.</span><span class="nx">filter</span><span class="p">(</span><span class="nx">n</span> <span class="o">=&gt;</span> <span class="nx">n</span><span class="p">)</span>
  <span class="p">}</span>
  <span class="p">...</span>
<span class="p">}</span>
</code></pre></div></div>

<p>What you’re witnessing here is how
<a href="https://www.laputan.org/mud/">balls of mud</a> begin to form. The wrong
abstraction was chosen for <code class="language-plaintext highlighter-rouge">Point</code>, so logic has begun accumulating
instead of being decomposed. The former version was compact and
bootstrapped from a more general concept, whereas the latter must know
about everything to accomplish its goal.</p>

<p>Also notice how much harder it is to understand the latter version,
instead of taking it in at a glance you have to understand the goal of
the low level transformations. Genies might be able to determine that
rapidly, but it takes more tokens to do so and over an entire codebase
this can lead to slower and more expensive development costs.</p>

<h1 id="unnecessary-weight">Unnecessary Weight</h1>

<p>Because Javascript’s <code class="language-plaintext highlighter-rouge">Set</code> implementation would not work as expected
(the abstraction is
<a href="https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/">leaky</a>),
I had to develop <code class="language-plaintext highlighter-rouge">PointSet</code> to handle these. The implementation is
rather boring, so I won’t share it here, but it’s a class I use all
over the place.</p>

<p>Part of what makes it so useful is that it conforms to the
<a href="https://en.wikipedia.org/wiki/Single-responsibility_principle">Single Responsibility Principle</a>.
It has one job and does it well, and I rarely think about how it
accomplishes its goal. Keeping <code class="language-plaintext highlighter-rouge">Point</code> to x/y coordinates is the
secret sauce of why I never have to think about it, to understand why
let’s explore what would happen if it included state.</p>

<p>If we include state as part of what makes a point unique, it could be
put in a state where the same coordinates can be in two states
simultaneously. Even if you never care about the state, it’s still
vulnerable to this kind of problem:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="kd">set</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PointSet</span><span class="p">()</span>
<span class="kd">set</span><span class="p">.</span><span class="nx">add</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="dl">"</span><span class="s2">B</span><span class="dl">"</span><span class="p">])</span>
<span class="kd">set</span><span class="p">.</span><span class="nx">add</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="dl">"</span><span class="s2">W</span><span class="dl">"</span><span class="p">])</span>
<span class="kd">set</span><span class="p">.</span><span class="nx">remove</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="dl">"</span><span class="s2">W</span><span class="dl">"</span><span class="p">])</span>
</code></pre></div></div>

<p>When <code class="language-plaintext highlighter-rouge">remove</code> is called, it’s reasonable to expect that <code class="language-plaintext highlighter-rouge">(0, 0)</code> is no
longer in the set. If you iterate over the members, though, you’ll
find that a phantom <code class="language-plaintext highlighter-rouge">[0, 0, "B"]</code> is still hanging around.</p>

<p>To address this, we could consider ignoring the state when it comes to
uniqueness. As long as you’re the only one to ever interact with the
class, it might be feasible to keep that detail in your head. Now that
we have genies, though, this is virtually never true. In my
experience, this manifests as a hallucination assuming that uniqueness
extends to the state. As a result, every interaction with the class
grows defensive logic, guarding against the possibility that an
existing point exists with a different state.</p>

<p>Both of these options are sub-optimal, and the consequences add weight
to interacting with the class. It’s a detail that needs to be tracked,
adding to either your mental or the genie’s context. If you try to
shed that weight, it results in subtle errors or superfluous code,
both of which simply shift the weight into debugging time or the
codebase.</p>

<h1 id="levels-of-abstraction">Levels of Abstraction</h1>

<p>Now we can finally discuss the group cache, which will use a two
tiered <code class="language-plaintext highlighter-rouge">Map</code> to provide rapid lookup.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">export</span> <span class="kd">class</span> <span class="nx">GroupCache</span> <span class="p">{</span>
  <span class="nl">groups</span><span class="p">:</span> <span class="nx">Groups</span>
  <span class="kd">constructor</span><span class="p">(</span><span class="nx">starting_groups</span><span class="p">?:</span> <span class="nx">Groups</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="nx">starting_groups</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">groups</span> <span class="o">=</span> <span class="nx">starting_groups</span>
    <span class="k">else</span> <span class="k">this</span><span class="p">.</span><span class="nx">groups</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Map</span><span class="p">()</span>
  <span class="p">}</span>

  <span class="nx">at</span><span class="p">(</span><span class="nx">point</span><span class="p">:</span> <span class="nx">Point</span><span class="p">):</span> <span class="nx">PointSet</span> <span class="o">|</span> <span class="kc">undefined</span> <span class="p">{</span>
    <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">point</span><span class="p">)</span><span class="o">!</span><span class="p">.</span><span class="nx">points</span>
  <span class="p">}</span>
  <span class="p">...</span>
<span class="p">}</span>
</code></pre></div></div>

<p>To add members to this cache, an <code class="language-plaintext highlighter-rouge">update</code> function is defined:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">update</span><span class="p">(</span><span class="nx">point</span><span class="p">:</span> <span class="nx">Point</span><span class="p">,</span> <span class="nx">state</span><span class="p">:</span> <span class="nx">State</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">this</span><span class="p">.</span><span class="nx">remove_from_existing_group</span><span class="p">(</span><span class="nx">point</span><span class="p">,</span> <span class="nx">state</span><span class="p">)</span>
  <span class="k">this</span><span class="p">.</span><span class="kd">set</span><span class="p">(</span><span class="nx">point</span><span class="p">,</span> <span class="p">{</span>
    <span class="nx">state</span><span class="p">,</span>
    <span class="na">points</span><span class="p">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">add_to_new_group</span><span class="p">(</span><span class="nx">point</span><span class="p">,</span> <span class="nx">state</span><span class="p">),</span>
  <span class="p">})</span>
<span class="p">}</span>
</code></pre></div></div>

<p>What’s important to understand here is that all of this logic operates
at the same level. No part of <code class="language-plaintext highlighter-rouge">at</code> or <code class="language-plaintext highlighter-rouge">update</code> looks inside of
<code class="language-plaintext highlighter-rouge">point</code>, they delegate to <code class="language-plaintext highlighter-rouge">get</code> and <code class="language-plaintext highlighter-rouge">set</code> to operate on those:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">private</span> <span class="kd">get</span><span class="p">([</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">]:</span> <span class="nx">Point</span><span class="p">):</span> <span class="nx">PointGroup</span> <span class="o">|</span> <span class="kc">undefined</span> <span class="p">{</span>
  <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">groups</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">x</span><span class="p">)?.</span><span class="kd">get</span><span class="p">(</span><span class="nx">y</span><span class="p">)</span>
<span class="p">}</span>

<span class="kr">private</span> <span class="kd">set</span><span class="p">([</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">]:</span> <span class="nx">Point</span><span class="p">,</span> <span class="nx">point_group</span><span class="p">:</span> <span class="nx">PointGroup</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">groups</span><span class="p">.</span><span class="nx">has</span><span class="p">(</span><span class="nx">x</span><span class="p">))</span> <span class="k">this</span><span class="p">.</span><span class="nx">groups</span><span class="p">.</span><span class="kd">set</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="k">new</span> <span class="nb">Map</span><span class="p">())</span>
  <span class="k">this</span><span class="p">.</span><span class="nx">groups</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span><span class="o">!</span><span class="p">.</span><span class="kd">set</span><span class="p">(</span><span class="nx">y</span><span class="p">,</span> <span class="nx">point_group</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>What’s interesting is that, although these operations aren’t complex,
they have some nuance protecting against common errors. For example,
<code class="language-plaintext highlighter-rouge">set</code> first ensures that the map exists for <code class="language-plaintext highlighter-rouge">x</code> before attempting to
call <code class="language-plaintext highlighter-rouge">set</code> on it. None of that matters from the perspective of
<code class="language-plaintext highlighter-rouge">update</code>, though, it can focus on what it means to update instead of
having to muck about with data structure massaging.</p>

<h1 id="genies">Genies</h1>

<p>As I’ve alluded to a few times, this kind of thinking and design
skills are precisely what’s needed when working with coding
assistants. My first attempt at creating this cache was done by Codex,
which tightly bound the cache to capturing rules from the
game. Sometimes that’s good enough, but in this case it fell apart
when I started tracking captures for scoring purposes.</p>

<p>When you take care to form clean abstractions, though, these
assistants can really sing. When I was working on
<code class="language-plaintext highlighter-rouge">remove_from_existing_group</code>, I needed to break apart a single
<code class="language-plaintext highlighter-rouge">PointSet</code> into subsets that were connected. This logic is a bit
hairy, but because the goal had such a clean definition, I was able to
generate that functionality rapidly.</p>

<p>The takeaway isn’t that genies are awful or wonderful, it’s to better
understand what they are good and bad at. This article explores that
boundary to help you better understand how to navigate it.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[A skill I often see underdeveloped in developers is layering simple abstractions. Maintaining this discipline is crucial in dodging code quagmires, which can be deadly when bugs occur. This has always been important, but because genies don’t understand this concept maintaining this quality is becoming central to the value we bring.]]></summary></entry><entry><title type="html">Attaching Properties to Abstractions</title><link href="https://blog.colinwilliams.name/2024/11/04/attaching-properties-to-abstractions.html" rel="alternate" type="text/html" title="Attaching Properties to Abstractions" /><published>2024-11-04T00:00:00+00:00</published><updated>2024-11-04T00:00:00+00:00</updated><id>https://blog.colinwilliams.name/2024/11/04/attaching-properties-to-abstractions</id><content type="html" xml:base="https://blog.colinwilliams.name/2024/11/04/attaching-properties-to-abstractions.html"><![CDATA[<p>A challenge around suggesting higher level properties is how to associate them to the abstractions they represent. For example, if I write a function like this:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">equals</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">x</span> <span class="o">==</span> <span class="nx">y</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>How would I know that this property is related to that function:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">property</span><span class="p">(</span>
    <span class="nx">integer</span><span class="p">(),</span> <span class="nx">integer</span><span class="p">(),</span>
    <span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">equals</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">)</span> <span class="o">==</span> <span class="nx">equals</span><span class="p">(</span><span class="nx">y</span><span class="p">,</span> <span class="nx">x</span><span class="p">),</span>
<span class="p">)</span>
</code></pre></div></div>

<p>Obviously it’s calling the function, but how do we figure out if the call is incidental or an attribute of the function itself. Static analysis is an option, but that can be challenging to build and sequencing the steps would be somewhat complex to orchestrate.</p>

<p>Other languages provide a way to annotate functions and classes, but in the Javascript world the only conversations I can find are around documentation. Javascript is a pretty dynamic language, though, so maybe there’s something clever we can do there. Here’s the property, definition and test reorganized a bit; it doesn’t get us where we want to go, but helps organize things a little differently.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">equals_property</span> <span class="o">=</span> <span class="nx">property</span><span class="p">(</span>
    <span class="nx">integer</span><span class="p">(),</span> <span class="nx">integer</span><span class="p">(),</span>
    <span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">equals</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">)</span> <span class="o">==</span> <span class="nx">equals</span><span class="p">(</span><span class="nx">y</span><span class="p">,</span> <span class="nx">x</span><span class="p">),</span>
<span class="p">)</span>
<span class="kd">function</span> <span class="nx">equals</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">x</span> <span class="o">==</span> <span class="nx">y</span><span class="p">;</span>
<span class="p">}</span>

<span class="nx">test</span><span class="p">(</span><span class="dl">"</span><span class="s2">symmetric</span><span class="dl">"</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="nx">assert</span><span class="p">(</span>
        <span class="nx">equals_property</span>
    <span class="p">)</span>
<span class="p">})</span>
</code></pre></div></div>

<p>One possible idea is to use first order functions to wrap function creation in a way that attaches a provide property:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">def</span><span class="p">(</span><span class="nx">property</span><span class="p">,</span> <span class="nx">func</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">func</span><span class="p">.</span><span class="nx">property</span> <span class="o">=</span> <span class="nx">property</span><span class="p">;</span>
    <span class="k">return</span> <span class="nx">func</span><span class="p">;</span>
<span class="p">}</span>

<span class="kd">const</span> <span class="nx">equals</span> <span class="o">=</span> <span class="nx">def</span><span class="p">(</span>
    <span class="nx">property</span><span class="p">(</span>
        <span class="nx">integer</span><span class="p">(),</span> <span class="nx">integer</span><span class="p">(),</span>
        <span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">equals</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">)</span> <span class="o">==</span> <span class="nx">equals</span><span class="p">(</span><span class="nx">y</span><span class="p">,</span> <span class="nx">x</span><span class="p">),</span>
    <span class="p">),</span>
    <span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">x</span> <span class="o">==</span> <span class="nx">y</span><span class="p">,</span>
<span class="p">)</span>

<span class="nx">test</span><span class="p">(</span><span class="dl">"</span><span class="s2">symmetric</span><span class="dl">"</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="nx">assert</span><span class="p">(</span>
        <span class="nx">equals</span><span class="p">.</span><span class="nx">property</span>
    <span class="p">)</span>
<span class="p">})</span>
</code></pre></div></div>

<p>So then it does seem possible to attach a property directly to the associated function. It might get a little complicated when we begin looking at defining objects like this, but this is enough to demonstrate that it’s possible to establish a direct link between a piece of logic and a property.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[A challenge around suggesting higher level properties is how to associate them to the abstractions they represent. For example, if I write a function like this:]]></summary></entry><entry><title type="html">Expression Substitution</title><link href="https://blog.colinwilliams.name/2024/11/03/expression-substitution.html" rel="alternate" type="text/html" title="Expression Substitution" /><published>2024-11-03T00:00:00+00:00</published><updated>2024-11-03T00:00:00+00:00</updated><id>https://blog.colinwilliams.name/2024/11/03/expression-substitution</id><content type="html" xml:base="https://blog.colinwilliams.name/2024/11/03/expression-substitution.html"><![CDATA[<p>I did a bit of hand waving around substituting expressions in my last post to prove out the idea of property inference, but these kinds of operations are anything but trivial. To examine this more thoroughly, let’s take an extremely simple function:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">equals</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">x</span> <span class="o">==</span> <span class="nx">y</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Let’s also take an extremely simple property related to this expression:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">property</span><span class="p">(</span>
    <span class="nx">integer</span><span class="p">(),</span> <span class="nx">integer</span><span class="p">(),</span>
    <span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">equals</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">)</span> <span class="o">==</span> <span class="nx">equals</span><span class="p">(</span><span class="nx">y</span><span class="p">,</span> <span class="nx">x</span><span class="p">),</span>
<span class="p">)</span>
</code></pre></div></div>

<p>Our goal is to identify some mechanism which can determine that such a property can be inferred in a function calling <code class="language-plaintext highlighter-rouge">equals</code>:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">double_equals</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">equals</span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="nx">x</span><span class="p">,</span> <span class="mi">2</span><span class="o">*</span><span class="nx">y</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Building this example, though, I’m beginning to see a counterexample to the original premise. Of course, <code class="language-plaintext highlighter-rouge">double_equals</code> retains the symmetry of <code class="language-plaintext highlighter-rouge">equals</code>, but something like this wouldn’t:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">is_double</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">equals</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="mi">2</span><span class="o">*</span><span class="nx">y</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Perhaps there’s a special circumstance when the structure of both arguments are identical, but this feels like it’s diving too heavily into the specifics of mathematics. It’s also possible there’s more advanced things to explore in this area, but I’m looking to tackle something less complex.</p>

<p>So instead of confidentally inferring all properties from lower level abstractions, I’m envisioning a system which can extrapolate candidates properties. It would propose symmentry for both <code class="language-plaintext highlighter-rouge">double_equals</code> and <code class="language-plaintext highlighter-rouge">is_double</code>, but leave it up to the user to determine its relevance. It also gives the user an opportunity to define a revised version of the property such as this:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">property</span><span class="p">(</span>
    <span class="nx">integer</span><span class="p">(),</span> <span class="nx">integer</span><span class="p">(),</span>
    <span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">is_double</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">)</span> <span class="o">==</span> <span class="nx">is_double</span><span class="p">(</span><span class="nx">y</span><span class="o">*</span><span class="mi">2</span><span class="p">,</span> <span class="nx">x</span><span class="o">/</span><span class="mi">2</span><span class="p">)</span>
<span class="p">)</span>
</code></pre></div></div>

<p>I didn’t achieve what I set out to at the beginning of this article, diving into the practical mechanics of substitution, but I was able to identify a flaw in the original approach. The original idea might eventually be possible, but this revised approach proves to be a much more tractable problem.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[I did a bit of hand waving around substituting expressions in my last post to prove out the idea of property inference, but these kinds of operations are anything but trivial. To examine this more thoroughly, let’s take an extremely simple function:]]></summary></entry><entry><title type="html">Rolling Up Properties</title><link href="https://blog.colinwilliams.name/2024/11/02/rolling-up-properties.html" rel="alternate" type="text/html" title="Rolling Up Properties" /><published>2024-11-02T00:00:00+00:00</published><updated>2024-11-02T00:00:00+00:00</updated><id>https://blog.colinwilliams.name/2024/11/02/rolling-up-properties</id><content type="html" xml:base="https://blog.colinwilliams.name/2024/11/02/rolling-up-properties.html"><![CDATA[<p>Now that I have a basic understanding of how the Javascript property libraries work, it’s time to shift my attention to examining my assumptions around the idea I’m attempting to explore. Generative testing promises to provide much more comprehensive of the properties which it can verify, and what I’d like to examine is if those attributes can be automatically composed when used in higher level abstractions.</p>

<p>I’ll use some simple mathematical properties as a way to explain what I mean. Consider, for example, a property true of the <code class="language-plaintext highlighter-rouge">&gt;</code> relationship:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">property</span><span class="p">(</span>
    <span class="nx">integer</span><span class="p">(),</span> <span class="nx">integer</span><span class="p">(),</span> <span class="nx">integer</span><span class="p">(),</span>
    <span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">,</span> <span class="nx">c</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="nx">a</span> <span class="o">&gt;</span> <span class="nx">b</span> <span class="o">&amp;&amp;</span> <span class="nx">b</span> <span class="o">&gt;</span> <span class="nx">c</span><span class="p">)</span> <span class="p">?</span> <span class="nx">a</span> <span class="o">&gt;</span> <span class="nx">c</span> <span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="p">)</span>
</code></pre></div></div>

<p>Here’s a simple function that could be built on top of that relationship:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">positive</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">x</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>We of course know that, if <code class="language-plaintext highlighter-rouge">j &gt; k</code> and <code class="language-plaintext highlighter-rouge">k</code> is positive, then <code class="language-plaintext highlighter-rouge">j</code> must also be positive. What I’m interesting in determining is if, because I defined the transitive property as a generative test, such a property could be automatically determined.</p>

<p>Before I embark on trying to pry apart the mechanics of how to figure something like that out, though, I need to validate this makes logical sense. To accomplish this, we somehow must infer that <code class="language-plaintext highlighter-rouge">c == 0</code> in the original property; perhaps easier said than done, but assuming it is determined leads to the following property:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">property</span><span class="p">(</span>
    <span class="nx">integer</span><span class="p">(),</span> <span class="nx">integer</span><span class="p">(),</span>
    <span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="nx">a</span> <span class="o">&gt;</span> <span class="nx">b</span> <span class="o">&amp;&amp;</span> <span class="nx">b</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">?</span> <span class="nx">a</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="p">)</span>
</code></pre></div></div>

<p>Then we can transform this again by replacing with the definition of <code class="language-plaintext highlighter-rouge">positive</code>:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">property</span><span class="p">(</span>
    <span class="nx">integer</span><span class="p">(),</span> <span class="nx">integer</span><span class="p">(),</span>
    <span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="nx">a</span> <span class="o">&gt;</span> <span class="nx">b</span> <span class="o">&amp;&amp;</span> <span class="nx">positive</span><span class="p">(</span><span class="nx">b</span><span class="p">))</span> <span class="p">?</span> <span class="nx">positive</span><span class="p">(</span><span class="nx">a</span><span class="p">)</span> <span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="p">)</span>
</code></pre></div></div>

<p>These transformations are far from trivial in most languages, but shows it’s at least possible to make logical transformations from base properties to more elaborate ones. This kind of meta-analysis might be more than Javascript is capable of in a practical way, but now I at least know it’s logically possible to reach such conclusions.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Now that I have a basic understanding of how the Javascript property libraries work, it’s time to shift my attention to examining my assumptions around the idea I’m attempting to explore. Generative testing promises to provide much more comprehensive of the properties which it can verify, and what I’d like to examine is if those attributes can be automatically composed when used in higher level abstractions.]]></summary></entry><entry><title type="html">Exploring Javascript Generative Testing</title><link href="https://blog.colinwilliams.name/2024/11/01/exploring-javascript-generative-testing.html" rel="alternate" type="text/html" title="Exploring Javascript Generative Testing" /><published>2024-11-01T00:00:00+00:00</published><updated>2024-11-01T00:00:00+00:00</updated><id>https://blog.colinwilliams.name/2024/11/01/exploring-javascript-generative-testing</id><content type="html" xml:base="https://blog.colinwilliams.name/2024/11/01/exploring-javascript-generative-testing.html"><![CDATA[<p>I’ve used generative testing on and off over the years, and want to explore it as a way to build more effective abstractions. I have been using Javascript as the primary language in my personal projects more recently, so to begin this research I want to better understand what’s available in the current landscape.</p>

<p>First, though, let me talk about what I’m looking to explore. A lot of people talk about how unit testing is a reasonable approximation for proving the correctness of a program, but what’s always sat uncomfortably with me is how easy it is to overlook corner cases. Generative testing offers the potential to more comprehensively cover a piece of code, and I wish to examine how it can be used to more comprehensively cover the contract it fulfills.</p>

<h1 id="testcheckjs"><a href="https://github.com/leebyron/testcheck-js">TestCheck.js</a></h1>

<p>A basic property is defined like this:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="p">{</span> <span class="nx">check</span><span class="p">,</span> <span class="nx">gen</span><span class="p">,</span> <span class="nx">property</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">testcheck</span><span class="dl">'</span><span class="p">);</span>

<span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">check</span><span class="p">(</span>
  <span class="nx">property</span><span class="p">(</span>
    <span class="nx">gen</span><span class="p">.</span><span class="nx">int</span><span class="p">,</span>
    <span class="nx">x</span> <span class="o">=&gt;</span> <span class="nx">x</span> <span class="o">-</span> <span class="nx">x</span> <span class="o">===</span> <span class="mi">0</span>
  <span class="p">)</span>
<span class="p">)</span>
</code></pre></div></div>

<p>I suppose I could write something to look at that result, but that can be a little clunky when I’m looking to use this frequently. It does offer test framework integration, but because it was last updated 6 years ago it doesn’t support <a href="https://vitest.dev/">Vitest</a> which appears to be the current front runner.</p>

<p>I can still wrap it in a test with an expectation, though, so still pretty easy to play around with:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">test</span><span class="p">(</span><span class="dl">"</span><span class="s2">x - x</span><span class="dl">"</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">check</span><span class="p">(</span>
        <span class="nx">property</span><span class="p">(</span>
            <span class="nx">gen</span><span class="p">.</span><span class="nx">int</span><span class="p">,</span>
            <span class="nx">x</span> <span class="o">=&gt;</span> <span class="nx">x</span> <span class="o">-</span> <span class="nx">x</span> <span class="o">===</span> <span class="mi">0</span>
        <span class="p">)</span>
    <span class="p">);</span>
    <span class="nx">expect</span><span class="p">(</span><span class="nx">result</span><span class="p">.</span><span class="nx">result</span><span class="p">).</span><span class="nx">toBeTruthy</span><span class="p">();</span>
<span class="p">});</span>
</code></pre></div></div>

<p>Here’s the basic call signature, stripped of specific examples:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">check</span><span class="p">(</span>
    <span class="nx">property</span><span class="p">(</span>
        <span class="nx">gen</span><span class="p">.</span><span class="o">&lt;</span><span class="nx">type</span><span class="o">&gt;</span><span class="p">,</span>
        <span class="o">&lt;</span><span class="nx">some</span> <span class="kd">function</span> <span class="nx">returning</span> <span class="nx">a</span> <span class="nx">boolean</span><span class="o">&gt;</span>
    <span class="p">),</span>
    <span class="o">&lt;</span><span class="nx">options</span><span class="o">&gt;</span>
<span class="p">)</span>
</code></pre></div></div>

<p>There are a ton of different generators, enough that most conceivable cases would be covered. It’s also possible to construct new generators by composing the ones provided, which gives a reasonable amount of extensibility.</p>

<h1 id="fast-check"><a href="https://github.com/dubzzz/fast-check">fast-check</a></h1>

<p>Fast Check appears to be more actively maintained and feature rich, but the documentation isn’t as well organized. The basic usage is pretty much identical:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">test</span><span class="p">(</span><span class="dl">"</span><span class="s2">x - x == 0</span><span class="dl">"</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="nx">fc</span><span class="p">.</span><span class="nx">assert</span><span class="p">(</span>
        <span class="nx">fc</span><span class="p">.</span><span class="nx">property</span><span class="p">(</span>
            <span class="nx">fc</span><span class="p">.</span><span class="nx">integer</span><span class="p">(),</span>
            <span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">x</span> <span class="o">-</span> <span class="nx">x</span> <span class="o">==</span> <span class="mi">0</span>
        <span class="p">)</span>
    <span class="p">)</span>
<span class="p">})</span>
</code></pre></div></div>

<p>Because it’s actively maintained, though, it supports modern testing libraries and so I didn’t have to examine the result to get the test to fail.</p>

<p>This library also seems to provide many generators which can be extended to check most things I could imagine.</p>

<h1 id="conclusion">Conclusion</h1>

<p>The basic footprint of all JS generative testing libraries is the same, although there only appears to be one library actively maintained. Even though it’s not too cumbersome, the footprint in both cases is a bit clunky and leads to a lot of extra code to transition between a simple test and a property based test.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[I’ve used generative testing on and off over the years, and want to explore it as a way to build more effective abstractions. I have been using Javascript as the primary language in my personal projects more recently, so to begin this research I want to better understand what’s available in the current landscape.]]></summary></entry></feed>