<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>samwho.dev</title>
    <subtitle>Personal website of Sam Rose.</subtitle>
    <link href="https://old.samwho.dev/rss.xml" rel="self" type="application/atom+xml"/>
    <link href="https://old.samwho.dev"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2025-08-23T00:00:00+00:00</updated>
    <id>https://old.samwho.dev/rss.xml</id>
    
        <entry xml:lang="en">
            <title>Big O</title>
            <published>2025-08-23T00:00:00+00:00</published>
            <updated>2025-08-23T00:00:00+00:00</updated>
            <author>
            <name>Unknown</name>
            </author>
            <link rel="alternate" href="https://old.samwho.dev/big-o/" type="text/html"/>
            <id>https://old.samwho.dev/big-o/</id>
            
            <content type="html">&lt;p&gt;&lt;s-hero role=&quot;heading&quot; aria-level=1 aria-label=&quot;Big O Notation&quot;&gt;&lt;&#x2F;s-hero&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Big O notation is a way of describing the performance of a function without
using time. Rather than timing a function from start to finish, big O describes
how the time grows as the input size increases. It is used to help understand
how programs will perform across a range of inputs.&lt;&#x2F;p&gt;
&lt;p&gt;In this post I&#x27;m going to cover 4 frequently-used categories of big O notation:
&lt;strong&gt;constant&lt;&#x2F;strong&gt;, &lt;strong&gt;logarithmic&lt;&#x2F;strong&gt;, &lt;strong&gt;linear&lt;&#x2F;strong&gt;, and &lt;strong&gt;quadratic&lt;&#x2F;strong&gt;. Don&#x27;t worry if
these words mean nothing to you right now. I&#x27;m going to talk about them in
detail, as well as visualise them, throughout this post.&lt;&#x2F;p&gt;
&lt;s-dog name=&quot;doe&quot;&gt;
  Before you scroll! This post has been sponsored by the wonderful folks at &lt;a
  href=&quot;https:&#x2F;&#x2F;ittybit.com&#x2F;?ref=sam&quot;&gt;ittybit&lt;&#x2F;a&gt;, and their API for working
  with videos, images, and audio. If you need to store, encode, or get
  intelligence from the media files in your app, check them out!
&lt;&#x2F;s-dog&gt;
&lt;h2 id=&quot;iterating&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#iterating&quot;&gt;#&lt;&#x2F;a&gt;
Iterating&lt;&#x2F;h2&gt;
&lt;p&gt;Consider this JavaScript function that calculates the sum of 1 to n.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript z-code&quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;sum&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;total&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-loop z-ts&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-increment z-ts&quot;&gt;++&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;total&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-compound z-ts&quot;&gt;+=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;total&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I&#x27;m going to pass in 1 billion, written using the shorthand &lt;code&gt;1e9&lt;&#x2F;code&gt;, so it takes a
noticeable amount of time to run. Press the &lt;h- key=&quot;run&quot;&gt;&lt;&#x2F;h-&gt; button below to
measure how long it takes to calculate the sum of 1 to 1 billion.&lt;&#x2F;p&gt;
&lt;s-code-timer title=&quot;sum(1e9)&quot;&gt;
function sum(n) {
  let total = 0;
  for (let i = 1; i &lt;= n; i++) {
    total += i;
  }
  return total;
}
const result = sum(1e9);
&lt;&#x2F;s-code-timer&gt;
&lt;p&gt;On my laptop this takes just under 1 second. The time you get may be different,
and it may vary by a few tens of milliseconds each time you run it. This is
expected.&lt;&#x2F;p&gt;
&lt;p&gt;Timing code this way, by taking the start time and the end time and finding the
difference, is called &lt;b&gt;wall-clock time&lt;&#x2F;b&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;How long do you think 2 billion, &lt;code&gt;2e9&lt;&#x2F;code&gt;, will take?&lt;&#x2F;p&gt;
&lt;s-code-timer title=&quot;sum(2e9)&quot;&gt;
function sum(n) {
  let total = 0;
  for (let i = 1; i &lt;= n; i++) {
    total += i;
  }
  return total;
}
const result = sum(2e9);
&lt;&#x2F;s-code-timer&gt;
&lt;p&gt;It takes about twice as long. The code loops &lt;code&gt;n&lt;&#x2F;code&gt; times and does a single
addition each time. If we passed in 3 billion, we would expect the execution
time to increase by a factor of three.&lt;&#x2F;p&gt;
&lt;s-dog position=&quot;right&quot; name=&quot;sage&quot; mode=&quot;proud&quot;&gt;
  The relationship between a function&#x27;s input and how long it takes to execute
  is called its &lt;b&gt;time complexity&lt;&#x2F;b&gt;, and &lt;b&gt;big O notation&lt;&#x2F;b&gt; is how we
  communicate what the time complexity of a function is.
&lt;&#x2F;s-dog&gt;
&lt;p&gt;Play around with the buttons below. Each bar adds an extra 1 billion to the &lt;code&gt;n&lt;&#x2F;code&gt;
that we pass to &lt;code&gt;sum&lt;&#x2F;code&gt;, so the &lt;h- key=&quot;run&quot;&gt;1e9&lt;&#x2F;h-&gt; button calls &lt;code&gt;sum(1e9)&lt;&#x2F;code&gt;,
the &lt;h- key=&quot;run&quot;&gt;2e9&lt;&#x2F;h-&gt; button calls &lt;code&gt;sum(2e9)&lt;&#x2F;code&gt;, and so on. You should see
&lt;code&gt;2e9&lt;&#x2F;code&gt; take about twice as long as &lt;code&gt;1e9&lt;&#x2F;code&gt;, and &lt;code&gt;3e9&lt;&#x2F;code&gt; take about three times as
long as &lt;code&gt;1e9&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;s-code-timer-bar-graph&gt;
  &lt;shared&gt;
    function sum(n) {
      let total = 0;
      for (let i = 1; i &lt;= n; i++) {
        total += i;
      }
      return total;
    }
  &lt;&#x2F;shared&gt;
  &lt;bar label=&quot;1e9&quot;&gt;sum(1e9);&lt;&#x2F;bar&gt;
  &lt;bar label=&quot;2e9&quot;&gt;sum(2e9);&lt;&#x2F;bar&gt;
  &lt;bar label=&quot;3e9&quot;&gt;sum(3e9);&lt;&#x2F;bar&gt;
  &lt;bar label=&quot;4e9&quot;&gt;sum(4e9);&lt;&#x2F;bar&gt;
  &lt;bar label=&quot;5e9&quot;&gt;sum(5e9);&lt;&#x2F;bar&gt;
&lt;&#x2F;s-code-timer-bar-graph&gt;
&lt;aside role=&quot;note&quot;&gt;
  &lt;small&gt;
    &lt;b&gt;Note&lt;&#x2F;b&gt;: On some browsers, you might experience bars taking a lot longer
    than they should. I wasn&#x27;t able to figure out why before publishing. If a
    bar seems way off what you would expect, try re-running it.
  &lt;&#x2F;small&gt;
&lt;&#x2F;aside&gt;
&lt;p&gt;Because &lt;code&gt;sum&lt;&#x2F;code&gt;&#x27;s wall-clock time grows at the same rate as &lt;code&gt;n&lt;&#x2F;code&gt;, e.g. &lt;code&gt;sum(20)&lt;&#x2F;code&gt;
would take twice as long as &lt;code&gt;sum(10)&lt;&#x2F;code&gt;, we say that &lt;code&gt;sum&lt;&#x2F;code&gt; is a &quot;linear&quot;
function. It has a big O of n, or &lt;strong&gt;O(n)&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;s-dog position=&quot;left&quot; name=&quot;haskie&quot; mode=&quot;confused&quot;&gt;
  Why do we use that syntax: &lt;b&gt;O(n)&lt;&#x2F;b&gt;? What is O? Why those brackets?
&lt;&#x2F;s-dog&gt;
&lt;p&gt;The &quot;O&quot; stands for &quot;order,&quot; short for &quot;order of growth.&quot; Said out loud it would
be: &quot;the order of growth of the &lt;code&gt;sum&lt;&#x2F;code&gt; function is n.&quot; &lt;strong&gt;O(n)&lt;&#x2F;strong&gt; is a compact way
to write that. The notation was created by the German mathematician Paul
Bachmann in 1894.  Also, the &quot;O&quot; (letter) might look like a 0 (number) in some
typefaces.  It is always the letter O.&lt;&#x2F;p&gt;
&lt;p&gt;A different way to sum the numbers from 1 to n is to use the formula &lt;code&gt;(n*(n+1))&#x2F;2&lt;&#x2F;code&gt;. Carl Friedrich Gauss discovered this formula in the early 1800s, and
it&#x27;s a clever way for us to avoid having to loop over all of the numbers.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s the result of this formula with the numbers from 1 to 5. In each case
the result should be the same as doing, e.g. &lt;code&gt;1+2+3+4+5&lt;&#x2F;code&gt; for &lt;code&gt;n=5&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;(1*2)&#x2F;2 = 2&#x2F;2  = 1&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;(2*3)&#x2F;2 = 6&#x2F;2  = 3&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;(3*4)&#x2F;2 = 12&#x2F;2 = 6&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;(4*5)&#x2F;2 = 20&#x2F;2 = 10&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;(5*6)&#x2F;2 = 30&#x2F;2 = 15&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Here&#x27;s how &lt;code&gt;sum&lt;&#x2F;code&gt; would look if it used that formula instead of the loop we had
before:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;sum&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;How do you think the wall-clock time of this function changes as &lt;code&gt;n&lt;&#x2F;code&gt; increases?
The next two examples &lt;strong&gt;differ by a factor of 100&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;s-code-timer title=&quot;sum(1e9)&quot;&gt;
function sum(n) {
  return (n * (n + 1)) &#x2F; 2;
}
const result = sum(1e9);
&lt;&#x2F;s-code-timer&gt;
&lt;s-code-timer title=&quot;sum(100e9)&quot;&gt;
function sum(n) {
  return (n * (n + 1)) &#x2F; 2;
}
const result = sum(100e9);
&lt;&#x2F;s-code-timer&gt;
&lt;p&gt;This example isn&#x27;t broken. Both of these functions take almost no time to at
all.  The variance in timing is caused by the browser, and the unpredictability
of computers, not the &lt;code&gt;sum&lt;&#x2F;code&gt; function.  Running each example a few times, you
should see that the wall-clock time hovers around the same value for both.&lt;&#x2F;p&gt;
&lt;p&gt;We call functions like this, whose wall-clock time is about the same no matter
what input you give it, &lt;strong&gt;constant&lt;&#x2F;strong&gt; or &lt;strong&gt;O(1)&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;s-dog position=&quot;left&quot; name=&quot;haskie&quot; mode=&quot;triumphant&quot;&gt;
  Wow, so we improved our sum function from &lt;b&gt;O(n)&lt;&#x2F;b&gt; to &lt;b&gt;O(1)&lt;&#x2F;b&gt;! It
  always runs instantly now!
&lt;&#x2F;s-dog&gt;
&lt;p&gt;We did! Though it is crucial to remember that &lt;strong&gt;O(1)&lt;&#x2F;strong&gt; doesn&#x27;t &lt;em&gt;always&lt;&#x2F;em&gt; mean
&quot;instant.&quot; It means that &lt;strong&gt;the time taken doesn&#x27;t increase with the size
of the input.&lt;&#x2F;strong&gt; In the case of our new &lt;code&gt;sum&lt;&#x2F;code&gt; function, it&#x27;s more or less
instant. But it&#x27;s possible for an &lt;strong&gt;O(1)&lt;&#x2F;strong&gt; algorithm to take several minutes or
even hours, depending on what it does.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s also possible for an &lt;strong&gt;O(n)&lt;&#x2F;strong&gt; algorithm to be faster than an &lt;strong&gt;O(1)&lt;&#x2F;strong&gt;
algorithm for some of its inputs. Eventually, though, the &lt;strong&gt;O(1)&lt;&#x2F;strong&gt; algorithm
will outpace the &lt;strong&gt;O(n)&lt;&#x2F;strong&gt; algorithm as the input size grows. Play with the
slider below to see an example of that.&lt;&#x2F;p&gt;
&lt;s-graph id=constantlinear style=&quot;width: 100%; aspect-ratio: 2&#x2F;1;&quot; drawupto=0&gt;
  &lt;legend position=top-left&gt;
  &lt;axes&gt;
    &lt;x tics=10 ticformat=&quot;tic.toFixed(0)&quot; max=100&gt;
    &lt;y tics=10 ticformat=&quot;tic.toFixed(0)&quot; max=110&gt;
  &lt;&#x2F;axes&gt;
  &lt;lines&gt;
    &lt;line label=&quot;O(n)&quot; y=&quot;5 + x&quot;&gt;
    &lt;line label=&quot;O(1)&quot; y=&quot;20&quot;&gt;
  &lt;&#x2F;lines&gt;
&lt;&#x2F;s-graph&gt;
&lt;input
  aria-label=&quot;A slider for controlling the graph lines&quot;
  style=&quot;margin-bottom: 2rem;&quot;
  type=&quot;range&quot;
  value=0
  min=0
  max=100
  step=any
  oninput=&quot;
    document.getElementById(&#x27;constantlinear&#x27;).setAttribute(&#x27;drawupto&#x27;, value)
  &quot;&gt;
&lt;&#x2F;input&gt;
&lt;s-dog position=&quot;left&quot; name=&quot;haskie&quot; mode=&quot;confused&quot;&gt;
  The &lt;b&gt;O(1)&lt;&#x2F;b&gt; line is always at 20 in that graph, so why don&#x27;t we say
  &lt;b&gt;O(20)&lt;&#x2F;b&gt; instead?
&lt;&#x2F;s-dog&gt;
&lt;p&gt;The purpose of big O notation is to describe the relationship between the input
and the wall-clock time of a function. It isn&#x27;t concerned with what that
wall-clock time ends up being, only with how it grows.&lt;&#x2F;p&gt;
&lt;p&gt;Big O always describes growth in the smallest terms possible.  It would quickly
get messy if the world had to figure out what number to put inside the brackets
for every function, and have those numbers be correct relative to each other.
Likewise, linear functions are always &lt;strong&gt;O(n)&lt;&#x2F;strong&gt; and never &lt;strong&gt;O(2n)&lt;&#x2F;strong&gt; or &lt;strong&gt;O(n +
1)&lt;&#x2F;strong&gt;, because &lt;strong&gt;O(n)&lt;&#x2F;strong&gt; is the smallest linear term.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sorting&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#sorting&quot;&gt;#&lt;&#x2F;a&gt;
Sorting&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s move away from &lt;code&gt;sum&lt;&#x2F;code&gt; and talk about a different algorithm: &lt;b&gt;bubble
sort&lt;&#x2F;b&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The idea behind bubble sort is that you loop over the input array and swap
elements next to each other if they are not in the desired order. You do this
until you&#x27;re able to complete a loop through the array without making any swaps.
It&#x27;s called bubble sort because of the way numbers &quot;bubble&quot; up to their correct
position.&lt;&#x2F;p&gt;
&lt;p&gt;Below is a JavaScript implementation of this algorithm. We&#x27;re going to sort
these numbers in ascending order, so the desired result is 1, 2, 3, 4, 5.&lt;&#x2F;p&gt;
&lt;p&gt;You can step through this code and watch the array get sorted using the
controls. &lt;h- key=&quot;step&quot;&gt;&lt;&#x2F;h-&gt; steps forwards 1 line at a time, &lt;h-
key=&quot;stepback&quot;&gt;&lt;&#x2F;h-&gt; steps backwards, &lt;h- key=&quot;play&quot;&gt;&lt;&#x2F;h-&gt; automatically
advances forward 1 line every second, and &lt;h- key=&quot;restart&quot;&gt;&lt;&#x2F;h-&gt; resets back to
the start.&lt;&#x2F;p&gt;
&lt;s-array ref=&quot;a&quot; debugger-id=&quot;bubble-sort-debugger&quot;&gt;
  &lt;annotation name=&quot;i&quot;&gt;&lt;&#x2F;annotation&gt;
  &lt;annotation name=&quot;i+1&quot;&gt;
    &lt;span data-name=&quot;i&quot;&gt;i&lt;&#x2F;span&gt;
    &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;+&lt;&#x2F;span&gt;
    &lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;
  &lt;&#x2F;annotation&gt;
&lt;&#x2F;s-array&gt;
&lt;div class=&quot;debugger-container&quot;&gt;
  &lt;s-debugger-controls debugger-id=&quot;bubble-sort-debugger&quot;&gt;
  &lt;&#x2F;s-debugger-controls&gt;
  &lt;s-debugger id=&quot;bubble-sort-debugger&quot;&gt;
    &lt;pre main&gt;
      function bubbleSort(a) {
        while(true) {
          let swapped = false;
          for (let i = 0; i &lt; a.length - 1; i++) {
            if (a[i] &gt; a[i+1]) {
              [a[i], a[i+1]] = [a[i+1], a[i]];
              swapped = true;
            }
          }
          if (!swapped) break;
        }
        return a;
      }
    &lt;&#x2F;pre&gt;
    &lt;pre&gt;
      bubbleSort([3, 2, 5, 4, 1]);
    &lt;&#x2F;pre&gt;
  &lt;&#x2F;s-debugger&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Now you&#x27;ve had a look at the algorithm in action, what do you think its big O
is?&lt;&#x2F;p&gt;
&lt;p&gt;If the array is already sorted, the algorithm loops through once, does no swaps,
and exits. This would be &lt;strong&gt;O(n)&lt;&#x2F;strong&gt;. But if the array is in any other order,
we need to loop through more than once. In the worst case, where the array is
in reverse order, we would have to loop through &lt;code&gt;n&lt;&#x2F;code&gt; times in order to move the
smallest element from the end to the start.&lt;&#x2F;p&gt;
&lt;p&gt;Looping through the &lt;code&gt;n&lt;&#x2F;code&gt; elements of our array &lt;code&gt;n&lt;&#x2F;code&gt; times results in &lt;code&gt;n*n&lt;&#x2F;code&gt;
operations, or &lt;code&gt;n^2&lt;&#x2F;code&gt;. That means &lt;strong&gt;bubble sort is an O(n^2) algorithm&lt;&#x2F;strong&gt;.
Sometimes called &lt;strong&gt;quadratic.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Because it&#x27;s common for an algorithm&#x27;s performance to depend not just on the
&lt;em&gt;size&lt;&#x2F;em&gt; of the input, but also its arrangement, &lt;strong&gt;big O notation always describes
the worst-case scenario&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;s-dog position=&quot;right&quot; name=&quot;sage&quot;&gt;
You may sometimes see the Greek letter &quot;theta&quot;, Θ, instead of the letter O in
big O notation. This is used when the best and worst case have the same order
of growth. We can&#x27;t use it for bubble sort because the best case is &lt;b&gt;O(n)&lt;&#x2F;b&gt;
and the worst case is &lt;b&gt;O(n^2)&lt;&#x2F;b&gt;.
&lt;&#x2F;s-dog&gt;
&lt;p&gt;Below is another way to visualise bubble sort. It starts off with the array 5,
4, 3, 2, 1 from top to bottom. The end state should be 1, 2, 3, 4, 5 top to
bottom. Each &lt;h- key=&quot;step&quot;&gt;&lt;&#x2F;h-&gt; step forward represents a full loop through
the array, potentially involving multiple swaps. Use &lt;h-&gt;Best&lt;&#x2F;h-&gt;,
&lt;h-&gt;Worst&lt;&#x2F;h-&gt;, and &lt;h-&gt;Rand&lt;&#x2F;h-&gt; to see different initial configurations.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;s-sort-grid array=&quot;5,4,3,2,1&quot;&gt;&lt;&#x2F;s-sort-grid&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If you played around with &lt;h-&gt;Rand&lt;&#x2F;h-&gt; a few times you&#x27;ll have noticed that you
do sometimes get only a couple of iterations. Despite this, bubble sort is still
&lt;strong&gt;O(n^2)&lt;&#x2F;strong&gt; because in the worst case you&#x27;ll have to iterate over the array
&lt;code&gt;n&lt;&#x2F;code&gt; times.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;searching&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#searching&quot;&gt;#&lt;&#x2F;a&gt;
Searching&lt;&#x2F;h2&gt;
&lt;p&gt;The last algorithm I want to talk about is &lt;strong&gt;binary search&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s start with a game. &lt;b&gt;Think of a number between 1 and 100.&lt;&#x2F;b&gt; I&#x27;m going
to try and guess what it is. Use the buttons below to tell me if your number is
higher or lower than my guess.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;s-higher-or-lower&gt;&lt;&#x2F;s-higher-or-lower&gt;&lt;&#x2F;p&gt;
&lt;p&gt;What I&#x27;m doing is starting in the middle of the range, 50, and eliminating half
of the possibilities with each guess. This is a &lt;b&gt;binary search&lt;&#x2F;b&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Using this method it will never take more than 7 guesses to find your number.
This is because we start with 100 possibilities and half of the possibilities
are ruled out with each guess.&lt;&#x2F;p&gt;
&lt;p&gt;The table below shows the guessing pattern for all numbers between 1 and 100,
use the slider to choose a number.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;s-higher-or-lower-table&gt;&lt;&#x2F;s-higher-or-lower-table&gt;&lt;&#x2F;p&gt;
&lt;p&gt;When it&#x27;s possible to eliminate a fraction of possibilities with every step
of an algorithm, we call it &lt;b&gt;logarithmic&lt;&#x2F;b&gt;. That means that binary search is
an &lt;strong&gt;O(log n)&lt;&#x2F;strong&gt; algorithm.&lt;&#x2F;p&gt;
&lt;p&gt;Below is a graph of the number of guesses I would need in order to figure out
your number for all of the numbers between 1 and 1000.&lt;&#x2F;p&gt;
&lt;s-graph id=guesses style=&quot;width: 100%; aspect-ratio: 2&#x2F;1;&quot; drawupto=0&gt;
  &lt;axes&gt;
    &lt;x tics=100 ticformat=&quot;tic.toFixed(0)&quot; label=&quot;Your number&quot; max=1000&gt;
    &lt;y tics=2 ticformat=&quot;tic.toFixed(0)&quot; label=&quot;Guesses&quot; max=10&gt;
  &lt;&#x2F;axes&gt;
  &lt;lines&gt;
    &lt;line label=&quot;Guesses&quot; y=&quot;Math.ceil(Math.log(x) &#x2F; Math.log(2))&quot;&gt;
  &lt;&#x2F;lines&gt;
&lt;&#x2F;s-graph&gt;
&lt;input
  aria-label=&quot;A slider for controlling the graph lines&quot;
  style=&quot;margin-bottom: 2rem;&quot;
  type=&quot;range&quot;
  value=0
  min=0
  max=1000
  step=any
  oninput=&quot;
    document.getElementById(&#x27;guesses&#x27;).setAttribute(&#x27;drawupto&#x27;, value)
  &quot;&gt;
&lt;&#x2F;input&gt;
&lt;p&gt;Every time your number doubles, I need 1 extra guess to find it. If you were to
pick a number between 1 and 1 billion, I would need 31 guesses at most to find
it. Logarithmic growth is really slow! Below is a graph comparing it to
&lt;strong&gt;O(n)&lt;&#x2F;strong&gt; and &lt;strong&gt;O(n^2)&lt;&#x2F;strong&gt;, which both grow much faster.&lt;&#x2F;p&gt;
&lt;s-graph id=graph2 style=&quot;width: 100%; aspect-ratio: 2&#x2F;1;&quot; drawupto=0&gt;
  &lt;legend position=top-left&gt;
  &lt;axes&gt;
    &lt;x tics=20 ticformat=&quot;tic.toFixed(0)&quot; max=100&gt;
    &lt;y tics=20 ticformat=&quot;tic.toFixed(0)&quot; max=100&gt;
  &lt;&#x2F;axes&gt;
  &lt;lines&gt;
    &lt;line label=&quot;O(n^2)&quot; y=&quot;Math.pow(x, 2)&quot;&gt;
    &lt;line label=&quot;O(n)&quot; y=&quot;x&quot;&gt;
    &lt;line label=&quot;O(log n)&quot; y=&quot;Math.log(x) &#x2F; Math.log(2)&quot;&gt;
  &lt;&#x2F;lines&gt;
&lt;&#x2F;s-graph&gt;
&lt;input
  aria-label=&quot;A slider for controlling the graph lines&quot;
  style=&quot;margin-bottom: 2rem;&quot;
  type=&quot;range&quot;
  value=0
  min=0
  max=100
  step=any
  oninput=&quot;
    document.getElementById(&#x27;graph2&#x27;).setAttribute(&#x27;drawupto&#x27;, value)
  &quot;&gt;
&lt;&#x2F;input&gt;
&lt;h2 id=&quot;putting-this-knowledge-to-work&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#putting-this-knowledge-to-work&quot;&gt;#&lt;&#x2F;a&gt;
Putting this knowledge to work&lt;&#x2F;h2&gt;
&lt;p&gt;In the previous sections of this post I&#x27;ve described the difference between
&lt;strong&gt;O(1)&lt;&#x2F;strong&gt;, &lt;strong&gt;O(log n)&lt;&#x2F;strong&gt;, &lt;strong&gt;O(n)&lt;&#x2F;strong&gt;, and &lt;strong&gt;O(n^2)&lt;&#x2F;strong&gt; algorithms. Let&#x27;s have a look
at some situations you might encounter while writing code and what you can do to
improve your time complexity.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;finding-an-item-in-a-list&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#finding-an-item-in-a-list&quot;&gt;#&lt;&#x2F;a&gt;
Finding an item in a list&lt;&#x2F;h3&gt;
&lt;p&gt;Here&#x27;s a function that checks if a list contains a specific item.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;contains&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;items&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;target&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-loop z-ts&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;item&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-of z-ts&quot;&gt;of&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;items&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;item&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-ts&quot;&gt;===&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;target&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-true z-ts&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-false z-ts&quot;&gt;false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you&#x27;re looking up items in the same list lots of times, you might want to
consider using a data structure that allows for faster lookups, such as a
&lt;strong&gt;Set&lt;&#x2F;strong&gt;. Modern browsers implement &lt;code&gt;Set&lt;&#x2F;code&gt; in a way that gives &lt;strong&gt;O(1)&lt;&#x2F;strong&gt;
time complexity for lookups.&lt;&#x2F;p&gt;
&lt;p&gt;However, don&#x27;t do this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;contains&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;items&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;target&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;itemSet&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Set&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;items&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;itemSet&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;has&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;target&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;em&gt;Building&lt;&#x2F;em&gt; the &lt;code&gt;new Set(items)&lt;&#x2F;code&gt; is an &lt;strong&gt;O(n)&lt;&#x2F;strong&gt; operation! This is because the
&lt;code&gt;Set&lt;&#x2F;code&gt; constructor loops over all items in the array to add them to the set. You
need to weigh the cost of this upfront work against the potential savings from
faster lookups.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;items&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Set&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;apple&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;banana&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;cherry&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;items&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;has&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;banana&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; true, and O(1)!&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;loop-an-array-with-indexes&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#loop-an-array-with-indexes&quot;&gt;#&lt;&#x2F;a&gt;
Loop an array with indexes&lt;&#x2F;h3&gt;
&lt;p&gt;The code below contains a common mistake I&#x27;ve seen dozens of times in production
code.  Have a read and see if you can answer:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;What is the big O of this function?&lt;&#x2F;li&gt;
&lt;li&gt;How could we improve it?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;buildList&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;items&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;output&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-loop z-ts&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;item&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-of z-ts&quot;&gt;of&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;items&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;index&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;items&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;indexOf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;item&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;output&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Item &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;index&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;: &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;item&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;output&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;join&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-ts&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The problem is calling &lt;code&gt;.indexOf&lt;&#x2F;code&gt; inside the loop. The &lt;code&gt;.indexOf&lt;&#x2F;code&gt; function is an
&lt;strong&gt;O(n)&lt;&#x2F;strong&gt; operation! It works by looping over the array until it finds the target
element, returning &lt;code&gt;null&lt;&#x2F;code&gt; if it doesn&#x27;t. Calling it inside the loop makes the
overall big O of our &lt;code&gt;buildList&lt;&#x2F;code&gt; function &lt;strong&gt;O(n^2)&lt;&#x2F;strong&gt;!&lt;&#x2F;p&gt;
&lt;p&gt;To fix this we can loop using an index. Looking up an element in an array by its
index is &lt;strong&gt;O(1)&lt;&#x2F;strong&gt;, so the overall big O of the function is reduced to &lt;strong&gt;O(n)&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;buildList&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;items&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;output&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-loop z-ts&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-relational z-ts&quot;&gt;&amp;lt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;items&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-ts&quot;&gt;length&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-increment z-ts&quot;&gt;++&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;output&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-template z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-begin z-ts&quot;&gt;`&lt;&#x2F;span&gt;Item &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;: &lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-begin z-ts&quot;&gt;${&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-template z-expression z-ts&quot;&gt;&lt;span class=&quot;z-meta z-embedded z-line z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;items&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-template-expression z-end z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-template z-end z-ts&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;output&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;join&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-ts&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can also achieve the same result with JavaScript&#x27;s &lt;code&gt;.forEach((item, index) =&amp;gt; {})&lt;&#x2F;code&gt; method on arrays, or &lt;code&gt;Object.entries()&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;caching-intermediate-results&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#caching-intermediate-results&quot;&gt;#&lt;&#x2F;a&gt;
Caching intermediate results&lt;&#x2F;h3&gt;
&lt;p&gt;Consider this function to calculate the factorial of a number. A factorial in
mathematics is written as, e.g., &lt;code&gt;5!&lt;&#x2F;code&gt; to represent &lt;code&gt;5*4*3*2*1&lt;&#x2F;code&gt; or &lt;code&gt;3!&lt;&#x2F;code&gt; to
represent &lt;code&gt;3*2*1&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;factorial&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-ts&quot;&gt;===&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;factorial&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This function has a time complexity of &lt;strong&gt;O(n)&lt;&#x2F;strong&gt;, but most calls to this function
are going to redo work we&#x27;ve done before. Calling &lt;code&gt;factorial(4)&lt;&#x2F;code&gt; and then
&lt;code&gt;factorial(5)&lt;&#x2F;code&gt; will mean &lt;code&gt;factorial(4)&lt;&#x2F;code&gt; is calculated twice.&lt;&#x2F;p&gt;
&lt;p&gt;We can cache the result of each calculation to avoid this redundant work.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;cache&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Map&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;factorial&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;cache&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;has&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;cache&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-ts&quot;&gt;===&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;result&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;factorial&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;cache&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;set&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;result&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This makes use of the &lt;strong&gt;O(1)&lt;&#x2F;strong&gt; time complexity for lookups in a &lt;code&gt;Map&lt;&#x2F;code&gt;.  It
doesn&#x27;t change the worst case time complexity of the &lt;code&gt;factorial&lt;&#x2F;code&gt; function, but
it does make the average case faster at the cost of increased memory usage.&lt;&#x2F;p&gt;
&lt;s-dog position=&quot;right&quot; name=&quot;sage&quot; mode=&quot;caution&quot;&gt;
  When it comes to performance, remember that you can&#x27;t ever take what you read
  online at face value. &lt;b&gt;Always test your code&lt;&#x2F;b&gt; before and after changes
  to make sure you&#x27;re actually improving it!
&lt;&#x2F;s-dog&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#conclusion&quot;&gt;#&lt;&#x2F;a&gt;
Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s recap what we&#x27;ve learned:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Big O notation describes the &lt;strong&gt;relationship between a function&#x27;s input and
its wall-clock time&lt;&#x2F;strong&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;From slowest growth to fastest growth we saw examples of:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;O(1)&lt;&#x2F;strong&gt;, constant time (best!)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;O(log n)&lt;&#x2F;strong&gt;, logarithmic time&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;O(n)&lt;&#x2F;strong&gt;, linear time&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;O(n^2)&lt;&#x2F;strong&gt;, quadratic time&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;We can improve the time complexity of the code we write by making better
algorithmic choices and avoiding common pitfalls.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These posts take me a long time to write, and they wouldn&#x27;t be possible without
the support of my family, friends, sponsors, and reviewers. I&#x27;m so grateful to
all of you—you know who you are—for making it possible for me to make these.&lt;&#x2F;p&gt;
&lt;p&gt;If you enjoyed this post, I&#x27;ve written a bunch more similar that you can find &lt;a
href=&quot;&#x2F;&quot;&gt;on my homepage&lt;&#x2F;a&gt;. I also love hearing from folks that have questions
or feedback, you can reach me via &lt;a href=&quot;mailto:big-o@samwho.dev&quot;&gt;email&lt;&#x2F;a&gt;,
on &lt;a href=&quot;https:&#x2F;&#x2F;bsky.app&#x2F;profile&#x2F;samwho.dev&quot;&gt;Bluesky&lt;&#x2F;a&gt;, or anonymously via
my &lt;a href=&quot;&#x2F;ping&quot;&gt;silly little ping service&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ll leave you with one last graph comparing all of the time complexities we
covered in this post.&lt;&#x2F;p&gt;
&lt;s-graph id=final style=&quot;width: 100%; aspect-ratio: 2&#x2F;1;&quot; drawupto=0&gt;
  &lt;legend position=top-left&gt;
  &lt;axes&gt;
    &lt;x tics=10 ticformat=&quot;tic.toFixed(0)&quot; max=50&gt;
    &lt;y tics=10 ticformat=&quot;tic.toFixed(0)&quot; max=50&gt;
  &lt;&#x2F;axes&gt;
  &lt;lines&gt;
    &lt;line label=&quot;O(1), constant&quot; y=&quot;1&quot;&gt;
    &lt;line label=&quot;O(log n), logarithmic&quot; y=&quot;Math.log(x) &#x2F; Math.log(2)&quot;&gt;
    &lt;line label=&quot;O(n), linear&quot; y=&quot;x&quot;&gt;
    &lt;line label=&quot;O(n^2), quadratic&quot; y=&quot;Math.pow(x, 2)&quot;&gt;
  &lt;&#x2F;lines&gt;
&lt;&#x2F;s-graph&gt;
&lt;input
  aria-label=&quot;A slider for controlling the graph lines&quot;
  style=&quot;margin-bottom: 2rem;&quot;
  type=&quot;range&quot;
  value=0
  min=0
  max=50
  step=any
  oninput=&quot;
    document.getElementById(&#x27;final&#x27;).setAttribute(&#x27;drawupto&#x27;, value)
  &quot;&gt;
&lt;&#x2F;input&gt;
</content>
            
        </entry>
    
    
        <entry xml:lang="en">
            <title>Reservoir Sampling</title>
            <published>2025-05-07T00:00:00+00:00</published>
            <updated>2025-05-07T00:00:00+00:00</updated>
            <author>
            <name>Unknown</name>
            </author>
            <link rel="alternate" href="https://old.samwho.dev/reservoir-sampling/" type="text/html"/>
            <id>https://old.samwho.dev/reservoir-sampling/</id>
            
            <content type="html">&lt;style&gt;
  header h1 {
    padding: 0;
    margin-top: 0.2rem;
    margin-bottom: 1rem;
  }

  button {
    margin: 0.5rem;
    padding: 0.5rem 1rem;
    background-color: #444444;
    color: white;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    touch-action: manipulation;
    user-select: none;
  }

  button:hover:not(:disabled) {
    background-color: #555555;
    touch-action: manipulation;
    user-select: none;
  }

  button:disabled {
    filter: opacity(0.5);
    cursor: not-allowed;
    touch-action: manipulation;
    user-select: none;
  }

  input[type=&quot;range&quot;] {
    width: 100%;
    margin: 1rem 0;
  }

  .control {
    display: flex;
    justify-content: center;
    align-items: center;
    margin: 1rem 0;
  }

  .control label {
    margin-right: 1rem;
    white-space: nowrap;
  }

  .control input[type=&quot;range&quot;] {
    flex-grow: 1;
  }

  .odds {
    font-size: 1.2rem;
    font-family: var(--code-font);
    font-weight: bold;
    text-align: center;
    display: flex;
    justify-content: center;
    gap: 2rem;
    margin: 1rem 0;
  }

  .odds .hold {
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  .odds .replace {
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  .odds .hold .value {
    color: var(--palette-dark-blue);
    white-space: nowrap;
  }

  .odds .replace .value {
    color: var(--palette-red);
    white-space: nowrap;
  }

  article input {
    --c: var(--palette-orange);
    --l: 2px;
    --h: 30px;
    --w: 30px;

    width: 100%;
    height: var(--h);
    -webkit-appearance :none;
    -moz-appearance :none;
    appearance :none;
    background: none;
    cursor: pointer;
    overflow: hidden;
  }

  article input:focus-visible, article input:hover{
    --p: 25%;
  }

  article input[type=&quot;range&quot; i]::-webkit-slider-thumb{
    height: var(--h);
    width: var(--w);
    aspect-ratio: 1;
    border-radius: 50%;
    background: var(--c);
    border-image: linear-gradient(90deg,var(--c) 50%,#ababab 0) 0 1&#x2F;calc(50% - var(--l)&#x2F;2) 100vw&#x2F;0 100vw;
    -webkit-appearance: none;
    appearance: none;
    box-shadow: none;
    transition: .3s;
  }

  article input[type=&quot;range&quot;]::-moz-range-thumb {
    --h: 25px;
    --w: 25px;
    height: var(--h);
    width: var(--w);
    aspect-ratio: 1;
    border-radius: 50%;
    background: var(--c);
    border-image: linear-gradient(90deg,var(--c) 50%,#ababab 0) 0 1&#x2F;calc(50% - var(--l)&#x2F;2) 100vw&#x2F;0 100vw;
    -webkit-appearance: none;
    appearance: none;
    box-shadow: none;
    transition: .3s;
  }

  img.hero {
    --width: 200px;
    width: var(--width);
    max-width: var(--width);
    margin-top: calc(var(--width) * -0.5);
    margin-bottom: 1rem;
  }
&lt;&#x2F;style&gt;
&lt;p&gt;&lt;s-hero&gt;&lt;&#x2F;s-hero&gt;&lt;&#x2F;p&gt;
&lt;a href=&quot;&#x2F;&quot;&gt;
    &lt;img class=&quot;hero&quot; alt=&quot;samwho keyboard logo&quot; src=&quot;&#x2F;images&#x2F;samwho-keyslogo.svg&quot; &#x2F;&gt;
&lt;&#x2F;a&gt;
&lt;header&gt;
  &lt;h1&gt;Reservoir Sampling&lt;&#x2F;h1&gt;
  &lt;section class=&quot;post-meta&quot; aria-label=&quot;published on 7th of May 2025&quot;&gt;
      2025-05-07
  &lt;&#x2F;section&gt;
&lt;&#x2F;header&gt;
&lt;p&gt;Reservoir sampling is a technique for selecting a fair random sample when you
don&#x27;t know the size of the set you&#x27;re sampling from. By the end of this essay
you will know:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;When you would need reservoir sampling.&lt;&#x2F;li&gt;
&lt;li&gt;The mathematics behind how it works, using only basic operations:
subtraction, multiplication, and division. No math notation, I promise.&lt;&#x2F;li&gt;
&lt;li&gt;A simple way to implement reservoir sampling if you want to use it.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;s-dog name=&quot;doe&quot;&gt;
  Before you scroll! This post has been sponsored by the wonderful folks at &lt;a
  href=&quot;https:&#x2F;&#x2F;ittybit.com&#x2F;?ref=sam&quot;&gt;ittybit&lt;&#x2F;a&gt;, and their API for working
  with videos, images, and audio. If you need to store, encode, or get
  intelligence from the media files in your app, check them out!
&lt;&#x2F;s-dog&gt;
&lt;h2 id=&quot;sampling-when-you-know-the-size&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#sampling-when-you-know-the-size&quot;&gt;#&lt;&#x2F;a&gt;
Sampling when you know the size&lt;&#x2F;h2&gt;
&lt;p&gt;In front of you are 10 playing cards and I ask you to pick 3 at random. How do
you do it?&lt;&#x2F;p&gt;
&lt;p&gt;The first technique that might come to mind from your childhood is to mix them
all up in the middle. Then you can straighten them out and pick the first 3.
You can see this happen below by clicking &quot;Shuffle.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;s-random-shuffle id=&quot;random-shuffle&quot;&gt;&lt;&#x2F;s-random-shuffle&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Every time you click &quot;Shuffle,&quot; the chart below tracks what the first 3 cards
were.&lt;&#x2F;p&gt;
&lt;s-card-select-bar-chart id=&quot;random-shuffle-chart&quot; target=&quot;random-shuffle&quot;&gt;
&lt;&#x2F;s-card-select-bar-chart&gt;
&lt;p&gt;At first you&#x27;ll notice some cards are selected more than others, but if you
keep going it will even out. All cards have an equal chance of being selected.
This makes it &quot;fair.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;Click &quot;Shuffle 100 times&quot; until the chart evens out.  You can reset the chart if
you&#x27;d like to start over.&lt;&#x2F;p&gt;
&lt;div style=&quot;display: flex; justify-content: center; padding-bottom: 1.5rem;&quot;&gt;
  &lt;button onclick=&quot;document.querySelector(&#x27;#random-shuffle&#x27;).shuffle({ n: 100 })&quot;&gt;
    Shuffle 100 times
  &lt;&#x2F;button&gt;
  &lt;button onclick=&quot;document.querySelector(&#x27;#random-shuffle-chart&#x27;).reset()&quot;&gt;
    Reset
  &lt;&#x2F;button&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;This method works fine with 10 cards, but what if you had 1 million cards?
Mixing those up won&#x27;t be easy. Instead, we could use a random number generator
to pick 3 indices. These would be our 3 chosen cards.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;s-random-select id=&quot;random-select&quot;&gt;&lt;&#x2F;s-random-select&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We no longer have to move all of the cards, and if we click the &quot;Select&quot; button
enough times we&#x27;ll see that this method is just as fair as the mix-up method.&lt;&#x2F;p&gt;
&lt;s-card-select-bar-chart id=&quot;random-select-chart&quot; target=&quot;random-select&quot;&gt;
&lt;&#x2F;s-card-select-bar-chart&gt;
&lt;div style=&quot;display: flex; justify-content: center; padding-bottom: 1.5rem;&quot;&gt;
  &lt;button onclick=&quot;document.querySelector(&#x27;#random-select&#x27;).select({ n: 100 })&quot;&gt;
    Select 100 times
  &lt;&#x2F;button&gt;
  &lt;button onclick=&quot;document.querySelector(&#x27;#random-select-chart&#x27;).reset()&quot;&gt;
    Reset
  &lt;&#x2F;button&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;I&#x27;m stretching the analogy a little here. It would take a long time to count
through the deck to get to, say, index 436,234. But when it&#x27;s an array in
memory, computers have no trouble finding an element by its index.&lt;&#x2F;p&gt;
&lt;p&gt;Now let me throw you a curveball: what if I were to show you 1 card at a time,
and you had to pick 1 at random?&lt;&#x2F;p&gt;
&lt;s-dog position=&quot;right&quot; mode=&quot;confused&quot;&gt;
  How many cards are you going to show me?
&lt;&#x2F;s-dog&gt;
&lt;p&gt;That&#x27;s the curveball: you don&#x27;t know.&lt;&#x2F;p&gt;
&lt;s-dog position=&quot;right&quot; mode=&quot;default&quot;&gt;
  Can I hold on to all the cards you give me and then pick 1 after you stop?
&lt;&#x2F;s-dog&gt;
&lt;p&gt;No, you can only hold on to 1 card at a time. You&#x27;re free to swap your card
with the newest one each time I show you a card, but you can only hold one and
you can&#x27;t go back to a card you&#x27;ve already seen.&lt;&#x2F;p&gt;
&lt;s-dog position=&quot;right&quot; mode=&quot;concerned&quot;&gt;
  Then it&#x27;s impossible! Why would I ever need to do this anyway?
&lt;&#x2F;s-dog&gt;
&lt;p&gt;Believe it or not, this is a real problem and it has a real and elegant
solution.&lt;&#x2F;p&gt;
&lt;p&gt;For example, let&#x27;s say you&#x27;re building a log collection service. Text logs, not
wooden ones. This service receives log messages from other services and
stores them so that it&#x27;s easy to search them in one place.&lt;&#x2F;p&gt;
&lt;p&gt;One of the things you need to think about when building a service like this is
what do you do when another service starts sending you way too many logs.  Maybe
it&#x27;s a bad release, maybe one of your videos goes viral. Whatever the reason, it
threatens to overwhelm your log collection service.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s simulate this. Below you can see a stream of logs that experiences
periodic spikes. A horizontal line indicates the &lt;h-&gt;threshold&lt;&#x2F;h-&gt; of logs per
second that the log collection service can handle, which in this example is 5
logs per second.&lt;&#x2F;p&gt;
&lt;!--
Yes, this is not web scale.
--&gt;
&lt;p&gt;&lt;s-log-stream
  id=&quot;spiky-logs-1&quot;
  mps=&quot;3&quot;
  peak-duration=&quot;2&quot;
  trough-duration=&quot;3&quot;
  peak-multiplier=&quot;6&quot;
  ramp-duration=&quot;1&quot;
  jitter=&quot;0.9,1.1&quot;&gt;
&lt;&#x2F;s-log-stream&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;s-spark-lines
  target=&quot;spiky-logs-1&quot;
  max-height=&quot;30&quot;
  hide-total=&quot;true&quot;
  red-line=&quot;5&quot;&gt;
&lt;&#x2F;s-spark-lines&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You can see that every so often, logs per second spikes above the
&lt;h-&gt;threshold&lt;&#x2F;h-&gt;. One way to deal with this is &quot;sampling.&quot; Deciding to send
only a fraction of the logs to the log collection service.  Let&#x27;s send 10% of
the logs.&lt;&#x2F;p&gt;
&lt;p&gt;Below we will see the same simulation again, but this time logs that don&#x27;t get
sent to our log collection service will be greyed out. The graph has 2 lines: a
black line tracks &lt;h-&gt;sent logs&lt;&#x2F;h-&gt;, the logs that are sent to our log
collection service, and a grey line tracks &lt;h-&gt;total logs&lt;&#x2F;h-&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;s-log-stream
  id=&quot;spiky-logs-2&quot;
  mps=&quot;3&quot;
  every-n=&quot;10&quot;
  peak-duration=&quot;2&quot;
  trough-duration=&quot;3&quot;
  peak-multiplier=&quot;6&quot;
  ramp-duration=&quot;1&quot;
  jitter=&quot;0.9,1.1&quot;&gt;
&lt;&#x2F;s-log-stream&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;s-spark-lines
  target=&quot;spiky-logs-2&quot;
  max-height=&quot;30&quot;
  red-line=&quot;5&quot;&gt;
&lt;&#x2F;s-spark-lines&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The rate of &lt;h-&gt;sent logs&lt;&#x2F;h-&gt; never exceeds the &lt;h-&gt;threshold&lt;&#x2F;h-&gt;, so we never
overwhelm our log collection service. However, in the quieter periods we&#x27;re
throwing away 90% of the logs when we don&#x27;t need to!&lt;&#x2F;p&gt;
&lt;p&gt;What we really want is to send &lt;em&gt;at most&lt;&#x2F;em&gt; 5 logs per second.  This would mean
that during quiet periods you get all the logs, but during spikes you discard
logs to protect the log collection service.&lt;&#x2F;p&gt;
&lt;p&gt;The simple way to achieve this would be to send the first 5 logs you see each
second, but this isn&#x27;t fair. You aren&#x27;t giving all logs an equal chance of being
selected.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sampling-when-you-don-t-know-the-size&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#sampling-when-you-don-t-know-the-size&quot;&gt;#&lt;&#x2F;a&gt;
Sampling when you don&#x27;t know the size&lt;&#x2F;h2&gt;
&lt;p&gt;We instead want to pick a fair sample of all the logs we see each second. The
problem is that we don&#x27;t know how many we will see. Reservoir sampling is an
algorithm that solves this exact problem.&lt;&#x2F;p&gt;
&lt;s-dog position=&quot;right&quot; mode=&quot;confused&quot;&gt;
  1 second isn&#x27;t a long time, can&#x27;t we just store all the messages we see and
  then use the select method from way back up there?
&lt;&#x2F;s-dog&gt;
&lt;p&gt;You &lt;em&gt;could&lt;&#x2F;em&gt;, but why live with that uncertainty?  You&#x27;d be holding on to an
unknown number of logs in memory. A sufficiently big spike could cause you
problems.  Reservoir sampling solves this problem, and does so without ever
using more memory than you ask it to.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s go back to our curveball of me showing you 1 card at a time.  Here&#x27;s a
recap of the rules:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;I&#x27;ll draw cards one at a time from a deck.&lt;&#x2F;li&gt;
&lt;li&gt;Each time I show you a card, you have to choose to hold it or discard it.&lt;&#x2F;li&gt;
&lt;li&gt;If you were already holding a card, you discard your held card before
replacing it with the new card.&lt;&#x2F;li&gt;
&lt;li&gt;At any point I can stop drawing cards and whatever card you&#x27;re holding is the
one you&#x27;ve chosen.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;How would you play this game in a way that ensures all cards have been given an
equal chance to be selected when I decide to stop?&lt;&#x2F;p&gt;
&lt;s-dog position=&quot;right&quot; mode=&quot;triumphant&quot;&gt;
  How about we flip a coin every new card? If it&#x27;s heads, we keep the card we
  have. If it&#x27;s tails, we swap it out for the new card.
&lt;&#x2F;s-dog&gt;
&lt;p&gt;You&#x27;re on the right track. Let&#x27;s have a look at how the coin flip idea plays out
in practice. Below you see a deck of cards. Clicking &quot;Deal&quot; will draw a card and
50% of the time it will go to the &lt;h-&gt;discard pile&lt;&#x2F;h-&gt; on the right, and 50% of
the time it will become your &lt;h-&gt;held card&lt;&#x2F;h-&gt; in the center, with any
previously held card moving to the discard pile.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;s-card-reservoir-sample
  method=&quot;coin-flip&quot;
  show-odds=&quot;false&quot;
  show-counts=&quot;true&quot;&gt;
&lt;&#x2F;s-card-reservoir-sample&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The problem is that while the &lt;h-&gt;hold&lt;&#x2F;h-&gt; vs &lt;h-&gt;discard&lt;&#x2F;h-&gt; counts are
roughly equal, which feels fair, later cards are much more likely to be held
when I stop than earlier cards. The first card drawn has to win 10 coin flips to
still be in your hand after the 10th card is drawn. The last card only has to
win 1.&lt;&#x2F;p&gt;
&lt;p&gt;Scrub the slider below to see how the chances change as we draw more cards. Each
bar represents a card in the deck, and the height of the bar is the chance we&#x27;re
holding that card when I stop. Below the slider are the chances we&#x27;re
holding the first card drawn vs. the last card drawn.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;s-card-odds-bar-chart&gt;&lt;&#x2F;s-card-odds-bar-chart&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Anything older than 15 cards ago is has a less than 0.01% chance of being held
when I stop.&lt;&#x2F;p&gt;
&lt;s-dog position=&quot;right&quot; mode=&quot;concerned&quot;&gt;
  You said I was on the right track! How can this be the right track when I&#x27;m
  more likely to win the lottery than to be holding the card I saw 24 draws ago?
&lt;&#x2F;s-dog&gt;
&lt;p&gt;Because believe it or not, we only have to make one small change to this idea
to make it fair.&lt;&#x2F;p&gt;
&lt;p&gt;Instead of flipping a coin to decide if we&#x27;ll hold the card or not, instead we
give each new card a &lt;code&gt;1&#x2F;n&lt;&#x2F;code&gt; chance of being held, where &lt;code&gt;n&lt;&#x2F;code&gt; is the number of
cards we&#x27;ve seen so far.&lt;&#x2F;p&gt;
&lt;s-dog position=&quot;right&quot; mode=&quot;concerned&quot;&gt;
  Wait, that&#x27;s it? That makes it fair?
&lt;&#x2F;s-dog&gt;
&lt;p&gt;Yep! In order to be fair, every card must have an equal chance of being
selected. So for the 2nd card, we want both cards to have a &lt;code&gt;1&#x2F;2&lt;&#x2F;code&gt; chance.  For
the 3rd card, we want all 3 cards to have a &lt;code&gt;1&#x2F;3&lt;&#x2F;code&gt; chance. For the 4th card, we
want all 4 cards to have a &lt;code&gt;1&#x2F;4&lt;&#x2F;code&gt; chance, and so on. So if we use &lt;code&gt;1&#x2F;n&lt;&#x2F;code&gt; for the
new card, we can at least say that the new card has had a fair shot.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s have a look at the chances as you draw more cards with this new
method.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;s-card-odds-bar-chart method=&quot;reservoir&quot; min-value=&quot;0.5&quot;&gt;&lt;&#x2F;s-card-odds-bar-chart&gt;&lt;&#x2F;p&gt;
&lt;s-dog position=&quot;right&quot; mode=&quot;confused&quot;&gt;
  I get how each &lt;b&gt;new&lt;&#x2F;b&gt; card has the right chance of being selected, but how
  does that make the &lt;b&gt;older&lt;&#x2F;b&gt; cards fair?
&lt;&#x2F;s-dog&gt;
&lt;p&gt;So far we&#x27;ve focused on the chance of the new card being selected, but we also
need to consider the chance of the card you&#x27;re holding staying in your hand.
Let&#x27;s walk through the numbers.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;card-1&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#card-1&quot;&gt;#&lt;&#x2F;a&gt;
Card 1&lt;&#x2F;h3&gt;
&lt;p&gt;The first card is easy: we&#x27;re not holding anything, so we always choose to hold
the first card. The chance we&#x27;re holding this card is &lt;code&gt;1&#x2F;1&lt;&#x2F;code&gt;, or &lt;code&gt;100%&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;div class=&quot;odds&quot;&gt;
  &lt;div class=&quot;hold&quot;&gt;
    &lt;div class=&quot;label&quot;&gt;
      Hold
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;value&quot;&gt;
      100%
    &lt;&#x2F;div&gt;
  &lt;&#x2F;div&gt;
  &lt;div class=&quot;replace&quot;&gt;
    &lt;div class=&quot;label&quot;&gt;
      Replace
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;value&quot;&gt;
      -
    &lt;&#x2F;div&gt;
  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;card-2&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#card-2&quot;&gt;#&lt;&#x2F;a&gt;
Card 2&lt;&#x2F;h3&gt;
&lt;p&gt;This time we have a real choice. We can keep hold of the card we have, or
replace it with the new one. We&#x27;ve said that we&#x27;re going to do this with a &lt;code&gt;1&#x2F;n&lt;&#x2F;code&gt;
chance, where &lt;code&gt;n&lt;&#x2F;code&gt; is the number of cards we&#x27;ve seen so far. So our chance of
replacing the first card is &lt;code&gt;1&#x2F;2&lt;&#x2F;code&gt;, or &lt;code&gt;50%&lt;&#x2F;code&gt;, and our chance of keeping hold of
the first card is its chance of being chosen last time multiplied by its chance
of not being replaced, so &lt;code&gt;100% * 1&#x2F;2&lt;&#x2F;code&gt;, which is again &lt;code&gt;50%&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;div class=&quot;odds&quot;&gt;
  &lt;div class=&quot;hold&quot;&gt;
    &lt;div class=&quot;label&quot;&gt;
      Hold
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;value&quot;&gt;
      100% * 1&#x2F;2
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;value&quot;&gt;
      50%
    &lt;&#x2F;div&gt;
  &lt;&#x2F;div&gt;
  &lt;div class=&quot;replace&quot;&gt;
    &lt;div class=&quot;label&quot;&gt;
      Replace
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;value&quot;&gt;
      1&#x2F;2
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;value&quot;&gt;
      50%
    &lt;&#x2F;div&gt;
  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;card-3&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#card-3&quot;&gt;#&lt;&#x2F;a&gt;
Card 3&lt;&#x2F;h3&gt;
&lt;p&gt;The card we&#x27;re holding has a &lt;code&gt;50%&lt;&#x2F;code&gt; chance of being there. This is true
regardless what happened up to this point. No matter whether we&#x27;re holding card
1 or card 2, it&#x27;s &lt;code&gt;50%&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The new card has a &lt;code&gt;1&#x2F;3&lt;&#x2F;code&gt; chance of being selected, so the card we&#x27;re holding has
a &lt;code&gt;1&#x2F;3&lt;&#x2F;code&gt; chance of being replaced. This means that our held card has a &lt;code&gt;2&#x2F;3&lt;&#x2F;code&gt;
chance of remaining held. So its chances of &quot;surviving&quot; this round are &lt;code&gt;50% * 2&#x2F;3&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;div class=&quot;odds&quot;&gt;
  &lt;div class=&quot;hold&quot;&gt;
    &lt;div class=&quot;label&quot;&gt;
      Hold
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;value&quot;&gt;
      50% * 2&#x2F;3
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;value&quot;&gt;
      33.33%
    &lt;&#x2F;div&gt;
  &lt;&#x2F;div&gt;
  &lt;div class=&quot;replace&quot;&gt;
    &lt;div class=&quot;label&quot;&gt;
      Replace
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;value&quot;&gt;
      1&#x2F;3
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;value&quot;&gt;
      33.33%
    &lt;&#x2F;div&gt;
  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;card-n&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#card-n&quot;&gt;#&lt;&#x2F;a&gt;
Card N&lt;&#x2F;h3&gt;
&lt;p&gt;This pattern continues for as many cards as you want to draw. We can express
both options as formulas.  Drag the slider to substitute &lt;code&gt;n&lt;&#x2F;code&gt; with real numbers
and see that the two formulas are always equal.&lt;&#x2F;p&gt;
&lt;div class=&quot;odds&quot;&gt;
  &lt;div class=&quot;hold&quot;&gt;
    &lt;div class=&quot;label&quot;&gt;
      Hold
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;value&quot; id=&quot;held&quot;&gt;
      1&#x2F;(n-1) * (1-(1&#x2F;n))
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;value&quot; id=&quot;hold-percent&quot;&gt;
      -
    &lt;&#x2F;div&gt;
  &lt;&#x2F;div&gt;
  &lt;div class=&quot;replace&quot;&gt;
    &lt;div class=&quot;label&quot;&gt;
      Replace
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;value&quot; id=&quot;replace&quot;&gt;
      1&#x2F;n
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;value&quot; id=&quot;replace-percent&quot;&gt;
      -
    &lt;&#x2F;div&gt;
  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;script&gt;
  const held = document.querySelector(&#x27;#held&#x27;);
  const holdPercent = document.querySelector(&#x27;#hold-percent&#x27;);
  const replace = document.querySelector(&#x27;#replace&#x27;);
  const replacePercent = document.querySelector(&#x27;#replace-percent&#x27;);

  function updateRangeValue(value) {
    const n = parseInt(value);
    if (n === 1) {
      held.innerText = &#x27;1&#x2F;(n-1) * (1-(1&#x2F;n))&#x27;;
      replace.innerText = &#x27;1&#x2F;n&#x27;;
      holdPercent.innerText = &#x27;-&#x27;;
      replacePercent.innerText = &#x27;-&#x27;;
      return;
    }
    held.innerText = `1&#x2F;(${n}-1) * (1-(1&#x2F;${n}))`;
    replace.innerText = `1&#x2F;${n}`;
    holdPercent.innerText = `${((1&#x2F;(n-1) * (1-(1&#x2F;n)))*100).toFixed(2)}%`;
    replacePercent.innerText = `${((1&#x2F;n) * 100).toFixed(2)}%`;
  }
&lt;&#x2F;script&gt;
&lt;input type=&quot;range&quot; min=&quot;1&quot; max=&quot;52&quot; value=&quot;1&quot; oninput=&quot;updateRangeValue(this.value)&quot; &#x2F;&gt;
&lt;p&gt;If &lt;code&gt;1&#x2F;n&lt;&#x2F;code&gt; is the chance of choosing the new card, &lt;code&gt;1&#x2F;(n-1)&lt;&#x2F;code&gt; is the chance of
choosing the new card from the previous draw. The chance of &lt;em&gt;not&lt;&#x2F;em&gt; choosing the
new card is the &lt;em&gt;complement&lt;&#x2F;em&gt; of &lt;code&gt;1&#x2F;n&lt;&#x2F;code&gt;, which is &lt;code&gt;1-(1&#x2F;n)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Below are the cards again except this time set up to use &lt;code&gt;1&#x2F;n&lt;&#x2F;code&gt; instead of a
coin flip. Click to the end of the deck. Does it feel fair to you?&lt;&#x2F;p&gt;
&lt;p&gt;&lt;s-card-reservoir-sample show-counts=&quot;true&quot;&gt;&lt;&#x2F;s-card-reservoir-sample&gt;&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s a good chance that through the 2nd half of the deck, you never swap
your chosen card. This &lt;em&gt;feels&lt;&#x2F;em&gt; wrong, at least to me, but as we saw above the
numbers say it is completely fair.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;choosing-multiple-cards&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#choosing-multiple-cards&quot;&gt;#&lt;&#x2F;a&gt;
Choosing multiple cards&lt;&#x2F;h2&gt;
&lt;p&gt;Now that we know how to select a single card, we can extend this to selecting
multiple cards. There are 2 changes we need to make:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Rather than new cards having a &lt;code&gt;1&#x2F;n&lt;&#x2F;code&gt; chance of being selected, they now have
a &lt;code&gt;k&#x2F;n&lt;&#x2F;code&gt; chance, where &lt;code&gt;k&lt;&#x2F;code&gt; is the number of cards we want to choose.&lt;&#x2F;li&gt;
&lt;li&gt;When we decide to replace a held card, we choose one of the &lt;code&gt;k&lt;&#x2F;code&gt; cards we&#x27;re
holding at random.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;So our new previous card selection formula becomes &lt;code&gt;k&#x2F;(n-1)&lt;&#x2F;code&gt; because we&#x27;re now
holding &lt;code&gt;k&lt;&#x2F;code&gt; cards. Then the chance that any of the cards we&#x27;re holding get
replaced is &lt;code&gt;1-(1&#x2F;n)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s see how this plays out with real numbers.&lt;&#x2F;p&gt;
&lt;div class=&quot;odds&quot;&gt;
  &lt;div class=&quot;hold&quot;&gt;
    &lt;div class=&quot;label&quot;&gt;
      Hold
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;value&quot; id=&quot;held2&quot;&gt;
      k&#x2F;(n-1) * (1-(1&#x2F;n))
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;value&quot; id=&quot;hold-percent2&quot;&gt;
      -
    &lt;&#x2F;div&gt;
  &lt;&#x2F;div&gt;
  &lt;div class=&quot;replace&quot;&gt;
    &lt;div class=&quot;label&quot;&gt;
      Replace
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;value&quot; id=&quot;replace2&quot;&gt;
      k&#x2F;n
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;value&quot; id=&quot;replace-percent2&quot;&gt;
      -
    &lt;&#x2F;div&gt;
  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;script&gt;
  const held2 = document.getElementById(&#x27;held2&#x27;);
  const holdPercent2 = document.getElementById(&#x27;hold-percent2&#x27;);
  const replace2 = document.getElementById(&#x27;replace2&#x27;);
  const replacePercent2 = document.getElementById(&#x27;replace-percent2&#x27;);

  function updateRangeValue2(value) {
    const k = 2;
    const n = parseInt(value);
    if (n === 2) {
      held2.innerText = &#x27;k&#x2F;(n-1) * (1-(1&#x2F;n))&#x27;;
      replace2.innerText = &#x27;k&#x2F;n&#x27;;
      holdPercent2.innerText = &#x27;-&#x27;;
      replacePercent2.innerText = &#x27;-&#x27;;
      return;
    }
    held2.innerText = `${k}&#x2F;(${n}-1) * (1-(1&#x2F;${n}))`;
    replace2.innerText = `${k}&#x2F;${n}`;
    holdPercent2.innerText = `${((k&#x2F;(n-1) * (1-(1&#x2F;n)))*100).toFixed(2)}%`;
    replacePercent2.innerText = `${((k&#x2F;n) * 100).toFixed(2)}%`;
  }
&lt;&#x2F;script&gt;
&lt;input type=&quot;range&quot; min=&quot;2&quot; max=&quot;52&quot; value=&quot;2&quot; oninput=&quot;updateRangeValue2(this.value)&quot; &#x2F;&gt;
&lt;p&gt;The fairness still holds, and will hold for any &lt;code&gt;k&lt;&#x2F;code&gt; and &lt;code&gt;n&lt;&#x2F;code&gt; pair. This is
because all held cards have an equal chance of being replaced, which keeps them
at an equal likelihood of still being in your hand every draw.&lt;&#x2F;p&gt;
&lt;p&gt;A nice way to implement this is to use an array of size &lt;code&gt;k&lt;&#x2F;code&gt;. For each new card,
generate a random number between 0 and &lt;code&gt;n&lt;&#x2F;code&gt;. If the random number is less than
&lt;code&gt;k&lt;&#x2F;code&gt;, replace the card at that index with the new card.  Otherwise, discard the
new card.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;s-card-reservoir-sample-2&gt;&lt;&#x2F;s-card-reservoir-sample-2&gt;&lt;&#x2F;p&gt;
&lt;p&gt;And that&#x27;s how reservoir sampling works!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;applying-this-to-log-collection&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#applying-this-to-log-collection&quot;&gt;#&lt;&#x2F;a&gt;
Applying this to log collection&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s take what we now know about reservoir sampling and apply it to our log
collection service. We&#x27;ll set &lt;code&gt;k=5&lt;&#x2F;code&gt;, so we&#x27;re &quot;holding&quot; at most 5 log messages
at a time, and every second we will send the selected logs to the log collection
service. After we&#x27;ve done that, we empty our array of size 5 and start again.&lt;&#x2F;p&gt;
&lt;p&gt;This creates a &quot;lumpy&quot; pattern in the graph below, and highlights a trade-off
when using reservoir sampling. It&#x27;s no longer a real-time stream of logs, but
chunks of logs sent at an interval. However, &lt;h-&gt;sent logs&lt;&#x2F;h-&gt; never exceeds
the &lt;h-&gt;threshold&lt;&#x2F;h-&gt;, and during quiet periods the two lines track each other
almost perfectly.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;s-log-stream
  id=&quot;spiky-logs-3&quot;
  mps=&quot;3&quot;
  peak-duration=&quot;2&quot;
  trough-duration=&quot;3&quot;
  peak-multiplier=&quot;6&quot;
  ramp-duration=&quot;1&quot;
  jitter=&quot;0.9,1.1&quot;
  reservoir-size=&quot;5&quot;&gt;
&lt;&#x2F;s-log-stream&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;s-spark-lines
  target=&quot;spiky-logs-3&quot;
  max-height=&quot;30&quot;
  red-line=&quot;5&quot;&gt;
&lt;&#x2F;s-spark-lines&gt;&lt;&#x2F;p&gt;
&lt;p&gt;No logs lost during quiet periods, and never more than &lt;h-&gt;threshold&lt;&#x2F;h-&gt; logs
per second sent during spikes.  The best of both worlds. It also doesn&#x27;t store
more than &lt;code&gt;k=5&lt;&#x2F;code&gt; logs, so it will have predictable memory usage.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;further-reading&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#further-reading&quot;&gt;#&lt;&#x2F;a&gt;
Further reading&lt;&#x2F;h2&gt;
&lt;p&gt;Something you may have thought while reading this post is that some logs are
more valuable than others. You almost certainly want to keep all error logs, for
example.&lt;&#x2F;p&gt;
&lt;p&gt;For that use-case there &lt;em&gt;is&lt;&#x2F;em&gt; a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Reservoir_sampling#Weighted_random_sampling&quot;&gt;weighted&lt;&#x2F;a&gt; variant of reservoir sampling. I
wasn&#x27;t able to find a simpler explanation of it, so that link is to Wikipedia
which I personally find a bit hard to follow. But the key point is that it
exists and if you need it you can use it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#conclusion&quot;&gt;#&lt;&#x2F;a&gt;
Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Reservoir sampling is one of my favourite algorithms, and I&#x27;ve been wanting to
write about it for years now. It allows you to solve a problem that at first
seems impossible, in a way that is both elegant and efficient.&lt;&#x2F;p&gt;
&lt;p&gt;Thank you again to &lt;a href=&quot;https:&#x2F;&#x2F;ittybit.com&#x2F;?ref=sam&quot;&gt;ittybit&lt;&#x2F;a&gt; for sponsoring this
post.  I really couldn&#x27;t have hoped for a more supportive first sponsor. Thank
you for believing in and understanding what I&#x27;m doing here.&lt;&#x2F;p&gt;
&lt;p&gt;Thank you to everyone who read this post and gave their feedback. You made this
post much better than I could have done on my own, and steered me away from
several paths that just weren&#x27;t working.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to tell me what you thought of this post by sending me an anonymous
message that goes directly to my phone, go to &lt;a href=&quot;https:&#x2F;&#x2F;samwho.dev&#x2F;ping&quot;&gt;https:&#x2F;&#x2F;samwho.dev&#x2F;ping&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
            
        </entry>
    
    
    
    
    
    
        <entry xml:lang="en">
            <title>Turing Machines</title>
            <published>2024-12-20T00:00:00+00:00</published>
            <updated>2024-12-20T00:00:00+00:00</updated>
            <author>
            <name>Unknown</name>
            </author>
            <link rel="alternate" href="https://old.samwho.dev/turing-machines/" type="text/html"/>
            <id>https://old.samwho.dev/turing-machines/</id>
            
            <content type="html">&lt;style&gt;
  body {
    text-wrap: pretty;
  }

  @media (prefers-reduced-motion: reduce) {
    * {
      transition: none;
      animation: none;
    }
  }

  turing-machine {
    width: 100%;
    display: block;
    position: relative;
    padding-bottom: 1em;
  }

  turing-machine .program-container {
    position: relative;
    display: flex;
    justify-content: center;
  }

  turing-machine table {
    border: none;
    font-family: var(--code-font);
    border-collapse: collapse;
    border-spacing: 0;
    margin: 1px;
    margin-top: 0.5em;
    width: auto;
  }

  turing-machine thead td {
    text-align: center;
  }

  turing-machine td {
    text-align: left;
    padding-left: 3vw;
    padding-right: 3vw;
    padding-top: 0.2em;
    padding-bottom: 0.2em;
    border: 1px dashed #bbbbbb;
  }

  turing-machine thead td {
    border: 0;
  }

  turing-machine .container {
    z-index: 1;
    background-color: white;
  }

  turing-machine .svg-container {
    padding-bottom: 1px;
    padding-top: 0.5em;
    line-height: 0;
    overflow-x: scroll;
    overflow-y: hidden;
    position: relative;
    scrollbar-width: none;
    cursor: grab;
    cursor: -webkit-grab;
  }

  turing-machine .svg-container::-webkit-scrollbar {
    display: none;
  }

  turing-machine .controls-container {
    line-height: 1.5;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.3em;
    margin-top: 0.2em;
    padding-bottom: 0.2em;
  }

  turing-machine .controls-container button {
    color: black;
    font-family: var(--code-font);
    background-color: #aaaaaa;
    border-radius: 30%&#x2F;50%;
    padding: 0.3em;
    height: 2em;
    min-width: 3em;
    text-align: center;
    border: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  turing-machine .controls-container button span {
    display: flex;
    align-items: center;
    justify-content: center;
  }

  turing-machine .controls-container img {
    width: 1rem;
    max-width: 1rem;
    margin: 0;
    display: inline-block;
  }

  turing-machine .controls-container select {
    color: black;
    border: 2px solid #aaaaaa;
    background-color: #ffffff;
    border-radius: 30%&#x2F;50%;
    padding: 0.15em;
    height: 2em;
    min-width: 3em;
    text-align: center;
    cursor: pointer;
    font-family: var(--code-font);
  }

  turing-machine .controls-container button:disabled {
    background-color: #eeeeee;
    color: #aaaaaa;
    cursor: auto;
  }

  turing-machine .controls-container button:disabled img {
    filter: opacity(0.3);
  }

  turing-machine .controls-container button:disabled:hover {
    background-color: #eeeeee;
  }

  turing-machine .controls-container button:hover {
    background-color: #999999;
  }

  turing-machine .controls-container button:active {
    background-color: #888888;
  }

  turing-machine .error {
    width: 80%;
    margin-top: 0.5em;
    margin-bottom: 0.5em;
    border-radius: 10px;
    background-color: #ffdddd;
    color: red;
    font-family: var(--code-font);
    font-size: 1.5em;
    font-weight: bold;
    text-align: center;
    margin: auto;
  }

  .dragging {
    cursor: grabbing !important;
    cursor: -webkit-grabbing !important;
  }

  .sticky {
    position: sticky !important;
    top: 0;
  }

  turing-machine .gradient {
    content: &quot;&quot;;
    z-index: 2;
    position: sticky;
    top: 0;
    left: 0;
    pointer-events: none;
    background-image: linear-gradient(90deg, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 20%, rgba(255,255,255,0) 80%, rgba(255,255,255,1) 100%);
    width: 100%;
    margin-top: -62px;
    height: 64px;
  }

  turing-machine svg {
    user-select: none;
    &#x2F;*touch-action: none;*&#x2F;
  }

  turing-machine svg text {
    font-family: var(--code-font);
  }

  turing-machine tr {
    padding-top: 0.5em;
    padding-bottom: 0.5em;
  }

  turing-machine .instruction {
    color: black;
    display: inline-block;
    border-radius: 0.5em;
    padding: 0.1em;
    min-width: 4.5ch;
    height: 100%;
    text-align: center;
  }

  turing-machine .pointer {
    display: inline-block;
    border-radius: 0.5em;
    position: absolute;
    z-index: -1;
  }

  turing-machine program {
    display: none;
  }

  turing-machine controls {
    display: none;
  }

  turing-machine.heading svg text {
    font-family: var(--heading-font);
    font-weight: bold;
  }

  figure.hero {
    font-family: var(--heading-font);
    text-align: center;
    padding-top: 1em;
    padding-bottom: 2em;
    margin-top: 1em;
    width: 100%;
    max-width: 100%;
  }

  figure.hero turing-machine {
    padding: 0;
    margin: 0;
  }

  figure.hero turing-machine .svg-container {
    margin: 0;
    padding-top: 0;
  }

  figure.hero turing-machine .gradient {
    top: 0;
  }

  figure.hero .signature {
    margin-top: 0.5rem;
    max-width: 200px;
  }

  figure.hero .portrait {
    margin-top: 1em;
    width: 250px;
    max-width: 250px;
  }

  figure.hero p {
    padding: 0;
    font-size: 0.9em;
  }

  figure.hero figcaption {
    font-family: var(--heading-font);
    font-style: small-caps;
    font-size: 0.8em;
  }

  @keyframes pulse {
    0% {
      transform: scale(1);
    }
    50% {
      transform: scale(1.1);
    }
    100% {
      transform: scale(1);
    }
  }

  .symbol {
    display: inline-block;
    border: 1px solid black;
    width: 1.5em;
    height: 1.5em;
    font-family: var(--code-font);
    text-align: center;
  }

  .inline-instruction {
    display: inline-block;
    font-family: var(--code-font);
    background-color: rgba(0, 158, 115, 0.7);
    color: black;
    border-radius: 0.5em;
    padding: 0.1em;
    min-width: 3ch;
    padding-left: 0.2em;
    padding-right: 0.2em;
    text-align: center;
  }

  li:has(.inline-instruction) {
    margin-top: 0.35em;
    margin-bottom: 0.35em;
  }

  .inline-state {
    display: inline-block;
    font-family: var(--code-font);
    background-color: rgb(86, 180, 233);
    color: black;
    border-radius: 0.5em;
    padding: 0.1em;
    min-width: 3ch;
    padding-left: 0.2em;
    padding-right: 0.2em;
    text-align: center;
  }

  li:has(.inline-state) {
    margin-top: 0.35em;
    margin-bottom: 0.35em;
  }

  .inline-value {
    display: inline-block;
    font-family: var(--code-font);
    background-color: rgb(230, 159, 0);
    color: black;
    border-radius: 0.5em;
    padding: 0.1em;
    min-width: 3ch;
    padding-left: 0.2em;
    padding-right: 0.2em;
    text-align: center;
  }

  li:has(.inline-value) {
    margin-top: 0.35em;
    margin-bottom: 0.35em;
  }

  figure {
    margin: auto;
    margin-top: 2em;
    margin-bottom: 2em;
    min-width: 0;
    max-width: 100%;
  }

  figure img {
    width: 400px;
    min-width: 0;
  }

  figure figcaption {
    max-width: 500px;
    color: #666;
    font-size: 0.8em;
    font-style: italic;
    text-align: center;
    font-family: var(--heading-font);
    text-wrap: pretty;
    margin: auto;
  }

  .media-icon {
    font-family: var(--code-font);
    background-color: #cccccc;
    border-radius: 30%&#x2F;50%;
    min-width: 2rem;
    height: 1.5rem;
    margin-right: 0.2rem;
    display: flex;
    align-items: center;
    justify-content: center;
    padding-right: 0.75rem;
    padding-left: 0.75rem;
  }

  .media-icon img {
    width: 0.75rem;
    flex-grow: 1;
  }

  .media-icon span {
    flex-grow: 1;
  }

  .post-meta {
    margin-top: 0.5rem;
    text-align: center;
    font-size: 0.9rem;
    font-family: var(--body-font);
    color: #4c566a;
  }
&lt;&#x2F;style&gt;
&lt;figure class=&quot;hero&quot;&gt;
  &lt;figcaption&gt;
    &lt;img class=&quot;signature&quot; src=&quot;&#x2F;images&#x2F;turing-signature.svg&quot; alt=&quot;Alan Turing&#x27;s written signature&quot; &#x2F;&gt;
    &lt;p&gt;&lt;b&gt;ALAN M. TURING&lt;&#x2F;b&gt;&lt;&#x2F;p&gt;
    &lt;p aria-label=&quot;Born 23rd June 1912, died 7th June 1954&quot;&gt;23 June 1912 – 7 June 1954&lt;&#x2F;p&gt;
  &lt;&#x2F;figcaption&gt;
  &lt;a href=&quot;&#x2F;&quot;&gt;
    &lt;img class=&quot;portrait&quot; src=&quot;&#x2F;images&#x2F;turing-sketch.png&quot; alt=&quot;A pencil drawing of Alan Turing, drawn by the post author Sam Rose.&quot; &#x2F;&gt;
  &lt;&#x2F;a&gt;
  &lt;turing-machine class=&quot;heading&quot; padding=0 show-head=false play=true&gt;
    &lt;program entrypoint=&quot;F&quot; show=&quot;false&quot;&gt;
      F |   |   P(T) R P(u) R P(r) R P(i) R P(n) R P(g) R P( ) R P(M) R P(a) R P(c) R P(h) R P(i) R P(n) R P(e) R P(s) R -&gt; B
      B |   | L P( ) L P( ) L P( ) L P( ) L P( ) L P( ) L P( ) L P( ) L P( ) L P( ) L P( ) L P( ) L P( ) L P( ) L P( )   -&gt; F
    &lt;&#x2F;program&gt;
  &lt;&#x2F;turing-machine&gt;
  &lt;section class=&quot;post-meta&quot; aria-label=&quot;published on 20th December 2024&quot;&gt;
      2024-12-20
  &lt;&#x2F;section&gt;
&lt;&#x2F;figure&gt;
&lt;noscript&gt;
  Looks like you&#x27;ve either disabled JavaScript, or your device doesn&#x27;t support
  JavaScript. Unfortunately, this page won&#x27;t work without it. I&#x27;m really sorry
  about that.
&lt;&#x2F;noscript&gt;
&lt;p&gt;&lt;em&gt;Translations: &lt;a href=&quot;&#x2F;turing-machines&quot;&gt;English&lt;&#x2F;a&gt;, &lt;a href=&quot;&#x2F;turing-machines-spanish&quot;&gt;Spanish&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In 1928, David Hilbert, one of the most influential mathematicians of his time,
asked whether it is possible to create an algorithm that could determine the
correctness of a mathematical statement. This was called the &quot;decision problem,&quot;
or &quot;Entscheidungsproblem&quot; in Hilbert&#x27;s native German. In 1936 both Alan Turing
and Alonzo Church independently reached the conclusion, using different methods,
that the answer is &quot;no.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;The way Turing did it was to imagine a &quot;universal machine&quot;, a machine that could
compute anything that could be computed. This idea, the &quot;Turing machine&quot; as
Alonzo Church christened it in 1937, laid the foundations for the device you are
using to read this post. If we look hard enough we can see Turing&#x27;s legacy in
today&#x27;s CPUs.&lt;&#x2F;p&gt;
&lt;p&gt;By the end of this post, you will know:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;What a Turing machine is.&lt;&#x2F;li&gt;
&lt;li&gt;What can and cannot be computed.&lt;&#x2F;li&gt;
&lt;li&gt;What it means to be Turing complete.&lt;&#x2F;li&gt;
&lt;li&gt;How modern computers relate to Turing machines.&lt;&#x2F;li&gt;
&lt;li&gt;How to write and run your own programs for a Turing machine.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;what-is-a-turing-machine&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#what-is-a-turing-machine&quot;&gt;#&lt;&#x2F;a&gt;
What &lt;em&gt;is&lt;&#x2F;em&gt; a Turing machine?&lt;&#x2F;h2&gt;
&lt;p&gt;You might expect a universal machine, capable of computing anything that can be
computed, to be a complex device. Nothing could be further from the truth. The
machine has just 4 parts, and the language used to program it has just 5
instructions.&lt;&#x2F;p&gt;
&lt;dog- name=&quot;sage&quot; position=&quot;right&quot;&gt;
  It&#x27;s important to keep in mind that what Turing described is a
  &lt;b&gt;theoretical&lt;&#x2F;b&gt; machine. It was created as a thought experiment to explore
  the limits of what can be computed. Some have of course &lt;a
  href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=vo8izCKHiF0&quot;&gt;been built&lt;&#x2F;a&gt;, but in 1936
  they existed only in the heads of Turing and those who read his paper.
&lt;&#x2F;dog-&gt;
&lt;p&gt;The parts are: a !tape, a !head, a !program, and a !state. When you&#x27;re ready,
go ahead and press !play.&lt;&#x2F;p&gt;
&lt;turing-machine&gt;
  &lt;controls&gt;&lt;&#x2F;controls&gt;
  &lt;program entrypoint=&quot;start&quot;&gt;
    start |   | P(0) R -&gt; start
  &lt;&#x2F;program&gt;
&lt;&#x2F;turing-machine&gt;
&lt;p&gt;What you&#x27;re seeing here is a program that executes &lt;span
class=&quot;inline-instruction&quot;&gt;P(0)&lt;&#x2F;span&gt; to print 0 to the tape, moves the head
right with the &lt;span class=&quot;inline-instruction&quot;&gt;R&lt;&#x2F;span&gt; instruction, then
!jumps back to the start. It will go on printing 0s forever.&lt;&#x2F;p&gt;
&lt;p&gt;At any point, feel free to !pause, step the machine !forwards or !backwards one
instruction at a time, or !restart the program from the beginning. There is also
a speed selector on the far right of the controls if you want to speed up the
machine.&lt;&#x2F;p&gt;
&lt;p&gt;Notice that !state and !value never change. Every time the machine performs a
!jump, the current state and value are used to pick the correct next row of
instructions to execute. This program only has a single state, &lt;span
class=&quot;inline-state&quot;&gt;start&lt;&#x2F;span&gt;, and every time it jumps, the symbol under the
!head is !blank.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s take a look at a program with multiple states.&lt;&#x2F;p&gt;
&lt;turing-machine&gt;
  &lt;controls&gt;&lt;&#x2F;controls&gt;
  &lt;program entrypoint=&quot;zero&quot;&gt;
    zero |   | P(0) R -&gt; one
    one  |   | P(1) R -&gt; zero
  &lt;&#x2F;program&gt;
&lt;&#x2F;turing-machine&gt;
&lt;p&gt;This program prints alternating 0s and 1s to the tape. It has 2 states, &lt;span
class=&quot;inline-state&quot;&gt;zero&lt;&#x2F;span&gt; and &lt;span class=&quot;inline-state&quot;&gt;one&lt;&#x2F;span&gt;, to
illustrate what happens when you !jump to a different state.&lt;&#x2F;p&gt;
&lt;dog- name=&quot;doe&quot;&gt;
  &lt;b&gt;Things moving too fast?&lt;&#x2F;b&gt; The slider below can be used to adjust the speed
  of all the Turing machines on this page.
  &lt;div style=&quot;width: 100%; display: flex; flex-wrap: wrap; gap: 0.5em; padding: 0.5em; padding-bottom: 0em;&quot;&gt;
    &lt;label for=&quot;speed&quot; id=&quot;speed-label&quot; style=&quot;min-width: 3em; text-align: right;&quot;&gt;100%&lt;&#x2F;label&gt;
    &lt;input
      type=&quot;range&quot;
      min=&quot;50&quot;
      max=&quot;200&quot;
      value=&quot;100&quot;
      id=&quot;speed&quot;
      style=&quot;flex-grow: 1; min-width: 0; width: 0;&quot;
      oninput=&quot;
        document.getElementById(&#x27;speed-label&#x27;).innerHTML = this.value + &#x27;%&#x27;;
        window.globalSpeedMultiplier = this.value &#x2F; 100;
      &quot;
    &#x2F;&gt;
  &lt;&#x2F;div&gt;
&lt;&#x2F;dog-&gt;
&lt;p&gt;You can also achieve this same result by using a single !state and alternating
the !value. Here&#x27;s an example of that:&lt;&#x2F;p&gt;
&lt;turing-machine&gt;
  &lt;controls&gt;&lt;&#x2F;controls&gt;
  &lt;program entrypoint=&quot;start&quot;&gt;
    start |   | R P(1) -&gt; start
    start | 1 | R P(0) -&gt; start
    start | 0 | R P(1) -&gt; start
  &lt;&#x2F;program&gt;
&lt;&#x2F;turing-machine&gt;
&lt;p&gt;The !value column always stays up to date with what the current symbol is under
the !head, then when we !jump that value is used to know which row of
instructions to execute. Combining state and value gives us a surprising amount
of control over what our !program does.&lt;&#x2F;p&gt;
&lt;p&gt;We&#x27;ve so far seen 3 instructions:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;inline-instruction&quot;&gt;P&lt;&#x2F;span&gt; prints a given symbol to the tape.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;span class=&quot;inline-instruction&quot;&gt;R&lt;&#x2F;span&gt; moves the tape head right.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;span class=&quot;inline-instruction&quot;&gt;↪︎&lt;&#x2F;span&gt; jumps to a given state.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;There are 2 more:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;inline-instruction&quot;&gt;L&lt;&#x2F;span&gt; moves the tape head left.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;span class=&quot;inline-instruction&quot;&gt;H&lt;&#x2F;span&gt; halts the machine.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;turing-machine&gt;
  &lt;controls&gt;&lt;&#x2F;controls&gt;
  &lt;program entrypoint=&quot;0&quot;&gt;
    0 |   | P(n) L -&gt; 1
    1 |   | P(a) L -&gt; 2
    2 |   | P(l) L -&gt; 3
    3 |   | P(A) H
  &lt;&#x2F;program&gt;
&lt;&#x2F;turing-machine&gt;
&lt;p&gt;This program prints the word &quot;Alan&quot; from right to left then halts. If you can&#x27;t
see the full word, you can drag the !tape left and right. If the machine has
halted, you can use !restart to start it again from the beginning.&lt;&#x2F;p&gt;
&lt;dog- name=&quot;haskie&quot; mode=&quot;concerned&quot; position=&quot;right&quot;&gt;
  You&#x27;re telling me that everything can be computed with just these 5
  instructions? Word processors, YouTube, video games, all of it?
&lt;&#x2F;dog-&gt;
&lt;p&gt;All of it! You&#x27;re probably not going to get Crysis running at 60fps on a
simulated Turing machine, but all of the calculations required to render each
frame can be done with just these 5 instructions. Everything you have ever seen
a computer do can be done with a Turing machine. We&#x27;ll see a glimpse of how
that can work in practice a little later.&lt;&#x2F;p&gt;
&lt;p&gt;The last example I want to show you before we move on is the very first program
Alan Turing showed the world. It&#x27;s the first program featured in his 1936 paper:
&lt;em&gt;&quot;On Computable Numbers, with an application to the Entsheidungsproblem.&quot;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;turing-machine&gt;
  &lt;controls&gt;&lt;&#x2F;controls&gt;
  &lt;program entrypoint=&quot;b&quot;&gt;
    b |   | P(0) R -&gt; c
    c |   | R -&gt; e
    e |   | P(1) R -&gt; k
    k |   | R -&gt; b
  &lt;&#x2F;program&gt;
&lt;&#x2F;turing-machine&gt;
&lt;p&gt;Turing liked to leave spaces between symbols, going as far as to even define
them as &quot;F-squares&quot; and &quot;E-squares&quot;. F for figure, and E for erasable. His
algorithms would often make use of E-squares to help the machine remember the
location of specific !tape squares.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-does-it-mean-to-compute&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#what-does-it-mean-to-compute&quot;&gt;#&lt;&#x2F;a&gt;
What does it mean to &lt;em&gt;compute&lt;&#x2F;em&gt;?&lt;&#x2F;h2&gt;
&lt;p&gt;Something is said to be &quot;computable&quot; if there exists an algorithm that can get
from the given input to the expected output. For example, adding together 2
integers is computable. Here I&#x27;m giving the machine a !tape that starts out with
the values 2 and 6 in binary separated by a !blank.&lt;&#x2F;p&gt;
&lt;turing-machine input=&quot;010 110&quot;&gt;
  &lt;controls&gt;&lt;&#x2F;controls&gt;
  &lt;program entrypoint=&quot;b1&quot;&gt;
    b1 | 0 | R -&gt; b1
    b1 | 1 | R -&gt; b1
    b1 |   | R -&gt; b2
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;b2 | 0 | R -&amp;gt; b2
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;b2 | 1 | R -&amp;gt; b2
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;b2 |   | L -&amp;gt; dec
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;dec | 0 | P(1) L -&amp;gt; dec
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;dec | 1 | P(0) L -&amp;gt; b3
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;dec |   | H
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;b3 | 0 | L -&amp;gt; b3
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;b3 | 1 | L -&amp;gt; b3
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;b3 |   | L -&amp;gt; inc
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;inc | 0 | P(1) R -&amp;gt; b1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;inc | 1 | P(0) L -&amp;gt; inc
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;inc |   | P(1) R -&amp;gt; b1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
  &lt;&#x2F;program&gt;
&lt;&#x2F;turing-machine&gt;
&lt;p&gt;This program adds the two numbers together, arriving at the answer 8. It does
this by decrementing from the right number and incrementing the left number
until the right number is 0. Here&#x27;s the purpose of each state:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;inline-state&quot;&gt;b1&lt;&#x2F;span&gt; Move right until the first !blank square
is found. This is to navigate past the first number.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;span class=&quot;inline-state&quot;&gt;b2&lt;&#x2F;span&gt; Move right until the second !blank
square is found. This is to navigate past the second number.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;span class=&quot;inline-state&quot;&gt;dec&lt;&#x2F;span&gt; Decrement the current number by 1. In
practice this will always be the right number. It decrements by flipping bits
until it either reaches a 1, where it will navigate back to the left number, or
a !blank, which it will interpret as the number having hit 0.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;span class=&quot;inline-state&quot;&gt;b3&lt;&#x2F;span&gt; Move left until the first !blank
square again. This is only ever used after we&#x27;ve decremented the rightmost
number. We can&#x27;t reuse the &lt;span class=&quot;inline-state&quot;&gt;b1&lt;&#x2F;span&gt; state here
because when we reach the !blank, we want to jump to &lt;span
class=&quot;inline-state&quot;&gt;inc&lt;&#x2F;span&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;span class=&quot;inline-state&quot;&gt;inc&lt;&#x2F;span&gt; Increment the current number by 1.
Similar to decrementing, this will only ever happen on the leftmost number in
practice. This is done by flipping bits until we reach a 0, at which point we
navigate back to the right number.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;That we can write this program at all is proof that addition is computable, but
it also implies that all integers are computable. If we can add any 2 integers,
we can compute any other integer. 1 is 0+1, 2 is 1+1, 3 is 2+1, and so on.&lt;&#x2F;p&gt;
&lt;dog- name=&quot;haskie&quot; mode=&quot;confused&quot;&gt;
  Why is the right number 111 and not 000 at the end of
  this program?
&lt;&#x2F;dog-&gt;
&lt;p&gt;It&#x27;s tricky to write the equivalent of &lt;code&gt;if (rightNum === 0) break;&lt;&#x2F;code&gt; in a Turing
machine, so this program does it as part of the decrementing process. If, while
decrementing, it gets all the way to a !blank square, it interprets that to mean
the number has hit 0 and halts.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;binary-vs-decimal&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#binary-vs-decimal&quot;&gt;#&lt;&#x2F;a&gt;
Binary vs Decimal&lt;&#x2F;h3&gt;
&lt;p&gt;You may have wondered why I&#x27;m choosing to work with binary numbers rather than
decimal. It&#x27;s not just because that&#x27;s how modern computers work. I&#x27;m going to
show you 2 examples, and from those examples you&#x27;ll be able to see &lt;em&gt;why&lt;&#x2F;em&gt; modern
computers choose to work in binary.&lt;&#x2F;p&gt;
&lt;p&gt;The first example is a program that increments a binary number in an endless
loop.&lt;&#x2F;p&gt;
&lt;turing-machine&gt;
  &lt;controls&gt;&lt;&#x2F;controls&gt;
  &lt;program entrypoint=&quot;move&quot;&gt;
    move | 1 | R -&gt; move
    move | 0 | R -&gt; move
    move |   | L -&gt; flip
    flip | 0 | P(1) R -&gt; move
    flip | 1 | P(0) L -&gt; flip
    flip |   | P(1) R -&gt; move
  &lt;&#x2F;program&gt;
&lt;&#x2F;turing-machine&gt;
&lt;p&gt;The second example is a program that increments a decimal number in an endless
loop.&lt;&#x2F;p&gt;
&lt;turing-machine input=&quot;0&quot;&gt;
  &lt;controls&gt;&lt;&#x2F;controls&gt;
  &lt;program entrypoint=&quot;inc&quot;&gt;
    inc    | 0 | P(1)   -&gt; back
    inc    | 1 | P(2)   -&gt; back
    inc    | 2 | P(3)   -&gt; back
    inc    | 3 | P(4)   -&gt; back
    inc    | 4 | P(5)   -&gt; back
    inc    | 5 | P(6)   -&gt; back
    inc    | 6 | P(7)   -&gt; back
    inc    | 7 | P(8)   -&gt; back
    inc    | 8 | P(9)   -&gt; back
    inc    | 9 | P(0) L -&gt; inc
    inc    |   | P(1)   -&gt; back
    back   |   | L -&gt; inc
    back   | * | R -&gt; back
  &lt;&#x2F;program&gt;
&lt;&#x2F;turing-machine&gt;
&lt;p&gt;These two programs are doing the same thing, but the program for manipulating
decimal numbers is much longer. We&#x27;ve even introduced some new syntax, the &lt;span
class=&quot;inline-value&quot;&gt;*&lt;&#x2F;span&gt; symbol, to handle a !value under the !head that
does not match any of the other values for that !state. It&#x27;s for this reason
when programming Turing machines we prefer binary numbers: the programs end up
being shorter and easier to reason about.&lt;&#x2F;p&gt;
&lt;p&gt;This benefit also translates to the physical world. Components that switch
between 2 states are cheaper, smaller, and more reliable than components that
switch between 10. It was more practical to build computers that worked in
binary than ones that work in decimal, though attempts to build decimal
computers &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Decimal_computer&quot;&gt;were made&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-can-t-be-computed&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#what-can-t-be-computed&quot;&gt;#&lt;&#x2F;a&gt;
What &lt;em&gt;can&#x27;t&lt;&#x2F;em&gt; be computed?&lt;&#x2F;h2&gt;
&lt;p&gt;To approach this question we need to explain the &quot;Halting problem.&quot; It goes like
this:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
Given a program and some input, is it possible to write a second program
that will tell you with certainty whether the first program will halt or run
forever?
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The answer is no, and this is what Turing essentially proved. The proof is
complicated and I&#x27;m not ashamed to admit I don&#x27;t understand it, but there is an
example I can give you that can be intuitively understood to be &quot;undecidable.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;Imagine you write a program that takes as its input the program being used to
decide whether it will halt or not. What it then does is run the decider program
on itself, and then do the opposite of what the decider program says.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;undecidable&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;willHalt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;willHalt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;undecidable&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-loop z-ts&quot;&gt;while&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-boolean z-true z-ts&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;else&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-boolean z-true z-ts&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This program intentionally enters an infinite loop if it is told it will halt,
and halts if it is told it will run forever. It seems like a silly example, the
kind of answer a cheeky high school student might try to get away with, but it
is a legitimate counterexample to the idea that the halting problem can be
solved.&lt;&#x2F;p&gt;
&lt;p&gt;If you were to imagine encoding the program and input into something that could
be represented on the !tape, there would be no !program that could determine
whether the program would halt or not. Imagining this encoding becomes quite
natural when you realise that modern programs are encoded as binary data to
be saved to disk.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-does-it-mean-to-be-turing-complete&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#what-does-it-mean-to-be-turing-complete&quot;&gt;#&lt;&#x2F;a&gt;
What does it mean to be &lt;em&gt;Turing complete&lt;&#x2F;em&gt;?&lt;&#x2F;h2&gt;
&lt;p&gt;If you&#x27;ve been involved in the world of programming for more than a few years,
there&#x27;s a good chance you&#x27;ve come across the term &quot;Turing complete.&quot; Most likely
in the context of things that really ought not to be Turing complete, like
&lt;a href=&quot;https:&#x2F;&#x2F;rtraba.com&#x2F;wp-content&#x2F;uploads&#x2F;2015&#x2F;05&#x2F;cppturing.pdf&quot;&gt;C++ templates&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;itnext.io&#x2F;typescript-and-turing-completeness-ba8ded8f3de3&quot;&gt;TypeScript&#x27;s type system&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;www.infoq.com&#x2F;articles&#x2F;excel-lambda-turing-complete&#x2F;&quot;&gt;Microsoft Excel&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;But what does it &lt;em&gt;mean&lt;&#x2F;em&gt;?&lt;&#x2F;p&gt;
&lt;p&gt;Like the Halting problem, the proof is complicated but there&#x27;s a straightforward
test you can apply to something to judge it Turing complete:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
  A system is Turing complete if it can be used to simulate a Turing machine.
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I&#x27;ve written this post, with the Turing machine simulations, in JavaScript.
Therefore JavaScript is Turing complete. The C++ template example given above
simulates a Turing machine in C++&#x27;s template system. The TypeScript example
takes the route of writing an interpreter for a different Turing complete
language.&lt;&#x2F;p&gt;
&lt;dog- name=&quot;haskie&quot; mode=&quot;confused&quot;&gt;
  Wait a second, wouldn&#x27;t you need an infinite amount of memory to simulate a
  Turing machine? Doesn&#x27;t the !tape extend forever in both directions?
&lt;&#x2F;dog-&gt;
&lt;p&gt;You&#x27;re right, and everyone tends to cheat a bit with the definition. When
someone says something is Turing complete, what they mean is it &lt;em&gt;would&lt;&#x2F;em&gt; be Turing
complete if it had an infinite amount of memory. The infinite tape limitation
means no Turing machine could ever exist in our physical reality, so that
requirement tends to get waived.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-does-this-all-relate-to-modern-computers&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#how-does-this-all-relate-to-modern-computers&quot;&gt;#&lt;&#x2F;a&gt;
How does this all relate to &lt;em&gt;modern computers&lt;&#x2F;em&gt;?&lt;&#x2F;h2&gt;
&lt;p&gt;If you read around the topic of Turing machines outside of this post, you might
see it said that modern computers are effectively Turing machines. You would be
forgiven for finding it difficult to imagine how you go from adding 2 integers
in binary on a !tape to running a web browser, but the line is there.&lt;&#x2F;p&gt;
&lt;p&gt;A key difference between our Turing machine and the device you&#x27;re reading this
on is that your device&#x27;s CPU has &quot;registers.&quot; These are small pieces of memory
that live directly on the CPU and are used to store values temporarily while
they&#x27;re being operated on. Values are being constantly loaded from memory into
registers and saved back again. You can think of registers as variables for your
CPU, but they can only store fixed-size numbers.&lt;&#x2F;p&gt;
&lt;p&gt;We &lt;em&gt;can&lt;&#x2F;em&gt; create registers in our Turing machine. We can do this by creating a
&quot;format&quot; for our tape.&lt;&#x2F;p&gt;
&lt;turing-machine input=&quot;HA000B000C000&quot;&gt;
&lt;&#x2F;turing-machine&gt;
&lt;p&gt;Here we define 3 registers: A, B, and C. Each register contains a 3 bits and can
store numbers between 0 and 7. Then at the far left we have an H, which stands
for &quot;home&quot;, which will help us navigate.&lt;&#x2F;p&gt;
&lt;p&gt;To increment register C, we can write a program like this:&lt;&#x2F;p&gt;
&lt;turing-machine input=&quot;HA000B000C000&quot;&gt;
  &lt;controls&gt;&lt;&#x2F;controls&gt;
  &lt;program entrypoint=&quot;goto_c&quot;&gt;
    goto_c | * | R -&gt; goto_c
    goto_c | C | R R R -&gt; inc
    inc    | 0 | P(1) -&gt; goto_h
    goto_h | * | L -&gt; goto_h
    goto_h | H | H
  &lt;&#x2F;program&gt;
&lt;&#x2F;turing-machine&gt;
&lt;p&gt;We&#x27;re making a lot more liberal use of the &lt;span class=&quot;inline-value&quot;&gt;*&lt;&#x2F;span&gt;
symbol here to help us navigate to specific parts of the !tape without having to
enumerate all possible values that could be under the !head on the way there.&lt;&#x2F;p&gt;
&lt;p&gt;This program is effectively equivalent to the following x86 assembly code, if
x86 had a register named &lt;code&gt;c&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;asm&quot; class=&quot;language-asm z-code&quot;&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;&lt;span class=&quot;z-source z-assembly&quot;&gt;&lt;span class=&quot;z-keyword z-control z-assembly&quot;&gt;mov&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-assembly&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-assembly&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-assembly&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-assembly&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-decimal z-assembly&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-assembly&quot;&gt; ; Load 0 into c&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-assembly&quot;&gt;&lt;span class=&quot;z-keyword z-control z-assembly&quot;&gt;inc&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-assembly&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-assembly&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-assembly&quot;&gt;    ; Increment c by 1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we wanted to add values in A and B, storing the result in C, we need to do
more work. Here&#x27;s the assembly code we&#x27;re trying to replicate:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;asm&quot; class=&quot;language-asm z-code&quot;&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;&lt;span class=&quot;z-source z-assembly&quot;&gt;&lt;span class=&quot;z-keyword z-control z-assembly&quot;&gt;mov&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-assembly&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-assembly&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-assembly&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-assembly&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-decimal z-assembly&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-assembly&quot;&gt;  ; Load 2 into a&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-assembly&quot;&gt;&lt;span class=&quot;z-keyword z-control z-assembly&quot;&gt;mov&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-assembly&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-assembly&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-assembly&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-assembly&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-decimal z-assembly&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-assembly&quot;&gt;  ; Load 3 into b&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-assembly&quot;&gt;&lt;span class=&quot;z-keyword z-control z-assembly&quot;&gt;add&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-assembly&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-assembly&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-assembly&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-assembly&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-assembly&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-assembly&quot;&gt;  ; Add a to c&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-assembly&quot;&gt;&lt;span class=&quot;z-keyword z-control z-assembly&quot;&gt;add&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-assembly&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-assembly&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-assembly&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-assembly&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-assembly&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-assembly&quot;&gt;  ; Add b to c&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Before you scroll down I will warn you that the program is long and complex. It
is the last program we will see in this post, and I don&#x27;t expect you to
understand it in full to continue to the end. Its main purpose is to show you
that we &lt;em&gt;can&lt;&#x2F;em&gt; implement operations seen in modern assembly code on a Turing
machine.&lt;&#x2F;p&gt;
&lt;turing-machine input=&quot;HA000B000C000&quot;&gt;
  &lt;controls&gt;&lt;&#x2F;controls&gt;
  &lt;program entrypoint=&quot;inita&quot;&gt;
    inita | * | R R P(0) R P(1) R P(0) R -&gt; initb
    initb | * | R P(0) R P(1) R P(1) R -&gt; start
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;start | * | L -&amp;gt; start
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;start | H | R -&amp;gt; go_a
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;go_a | * | R -&amp;gt; go_a
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;go_a | A | R R R -&amp;gt; dec_a
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;dec_a  | 0 | P(1) L -&amp;gt; cry_a
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;dec_a  | 1 | P(0) -&amp;gt; go_c1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;cry_a | 0 | P(1) L -&amp;gt; cry_a
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;cry_a | 1 | P(0) -&amp;gt; go_c1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;cry_a | * | R P(0) R P(0) R P(0) -&amp;gt; goto_b
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;go_c1 | * | R -&amp;gt; go_c1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;go_c1 | C | R R R -&amp;gt; inc_c1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;inc_c1 | 0 | P(1) -&amp;gt; h2a
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;inc_c1 | 1 | P(0) L -&amp;gt; cry_ca
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;cry_ca | 0 | P(1) -&amp;gt; h2a
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;cry_ca | 1 | P(0) L -&amp;gt; cry_ca
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;cry_ca | * | R -&amp;gt; h2a
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;h2a | * | L -&amp;gt; h2a
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;h2a | H | R -&amp;gt; go_a
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;goto_b | * | R -&amp;gt; goto_b
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;goto_b | B | R R R -&amp;gt; dec_b
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;dec_b | 0 | P(1) L -&amp;gt; dec_bc
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;dec_b | 1 | P(0) -&amp;gt; go_c2
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;dec_bc | 0 | P(1) L -&amp;gt; dec_bc
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;dec_bc | 1 | P(0) -&amp;gt; go_c2
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;dec_bc | * | R P(0) R P(0) R P(0) -&amp;gt; end
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;go_c2 | * | R -&amp;gt; go_c2
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;go_c2 | C | R R R -&amp;gt; inc_c2
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;inc_c2 | 0 | P(1) -&amp;gt; go_hb
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;inc_c2 | 1 | P(0) L -&amp;gt; cry_cb
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;cry_cb | 0 | P(1) -&amp;gt; go_hb
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;cry_cb | 1 | P(0) L -&amp;gt; cry_cb
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;cry_cb | * | R -&amp;gt; go_hb
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;go_hb | * | L -&amp;gt; go_hb
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;go_hb | H | R -&amp;gt; goto_b
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;end | * | L -&amp;gt; end
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;end | H | H
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
  &lt;&#x2F;program&gt;
&lt;&#x2F;turing-machine&gt;
&lt;p&gt;This is painfully laborious, and it doesn&#x27;t even precisely match the assembly
code. It destroys the values in A and B as it adds them together, and it doesn&#x27;t
handle overflow. But it&#x27;s a start, and I hope it gives you a glimpse of how this
theoretical machine can be built up to operate like a modern CPU.&lt;&#x2F;p&gt;
&lt;p&gt;If you watch the program run to completion, something that might strike you is
just how much work is required to do something as simple as adding 2 numbers.
Turing machines were not designed to be practical, Turing never intended anyone
to go out and build one of these machines in the hope it will be useful.&lt;&#x2F;p&gt;
&lt;p&gt;Modern machines have circuits within them that can add 2 numbers together by
passing 2 electrical signals in and getting the sum as a single signal out. This
happens in less than a nanosecond. Modern machines have memory where any byte
can be accessed at any time, no tape manipulation required. This memory access
takes a few dozen nanoseconds.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;writing-and-running-your-own-programs&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#writing-and-running-your-own-programs&quot;&gt;#&lt;&#x2F;a&gt;
Writing and running your own programs&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;ve built a web-based development environment for writing programs that will
run on the Turing machine visualisations you&#x27;ve seen throughout the post.&lt;&#x2F;p&gt;
&lt;p&gt;You can access the editor &lt;b&gt;&lt;a href=&quot;&#x2F;christopher&quot;&gt;here&lt;&#x2F;a&gt;&lt;&#x2F;b&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I encourage you to play around with it. Set a simple goal, like adding
together 2 numbers without going back to look at the way I did it in the post.
It&#x27;s a great way to get a feel for how the machine works.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#conclusion&quot;&gt;#&lt;&#x2F;a&gt;
Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;To recap, we&#x27;ve covered:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;What a Turing machine is.&lt;&#x2F;li&gt;
&lt;li&gt;What can and cannot be computed.&lt;&#x2F;li&gt;
&lt;li&gt;What it means to be Turing complete.&lt;&#x2F;li&gt;
&lt;li&gt;How modern computers relate to Turing machines.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;And you now have access to an environment for writing and running your own
Turing machine programs. If you use it to make something neat, please do reach
out to me and show me! My email address is &lt;a
href=&quot;mailto:hello@samwho.dev&quot;&gt;hello@samwho.dev&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;figure&gt;
  &lt;img style=&quot;max-width: 200px&quot; src=&quot;&#x2F;images&#x2F;turing-apple.png&quot; &#x2F;&gt;
  &lt;figcaption&gt;
    On June 8th, 1954, Alan Turing was found dead in bed, at his home in
    Wilmslow. He had died the day before, aged 41, from cyanide poisoning. A
    half-slice of apple was on his bedside table, laced with cyanide. An inquest
    ruled the death a suicide.
  &lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;further-reading&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#further-reading&quot;&gt;#&lt;&#x2F;a&gt;
Further reading&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;archive.org&#x2F;details&#x2F;Turing1936OnCumputableNumbers&#x2F;page&#x2F;n3&#x2F;mode&#x2F;2up&quot;&gt;Turing&#x27;s original paper&lt;&#x2F;a&gt; on computable numbers.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.charlespetzold.com&#x2F;AnnotatedTuring&#x2F;&quot;&gt;The Annotated Turing&lt;&#x2F;a&gt; I
referenced this throughout the making of this post. It is a fabulous read,
strongly recommend.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Alan_Turing:_The_Enigma&quot;&gt;Alan Turing: The Enigma&lt;&#x2F;a&gt;
by Andrew Hodges. An excellent biography of Turing, I read this during the
writing of this post.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;redfrontdoor.org&#x2F;turing-mandelbrot&#x2F;&quot;&gt;Calculating a Mandelbrot Set using a Turing
Machine&lt;&#x2F;a&gt;. This was exceptionally
useful for me to understand how to get from Turing machines to modern computers.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;figure&gt;
  &lt;img style=&quot;max-width: 200px; margin-bottom: 0.5em;&quot; src=&quot;&#x2F;images&#x2F;christopher-morcom.png&quot; &#x2F;&gt;
  &lt;figcaption&gt;
    Christopher Morcom, 13 July 1911 - 13 February 1930. Turing&#x27;s childhood
    friend and first love.
  &lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;acknowledgements&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#acknowledgements&quot;&gt;#&lt;&#x2F;a&gt;
Acknowledgements&lt;&#x2F;h2&gt;
&lt;p&gt;These posts are never a solo effort, and this one is no exception. Sincere thanks
go to the following people:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;To my wife, Sophie, who drew the biographical sketches you&#x27;re seeing at the
end here, and for putting up with my incessant talking about this post the
last 2 weeks.&lt;&#x2F;li&gt;
&lt;li&gt;Everyone who let me watch them read this post in real-time over a video call
and gave me feedback: &lt;a href=&quot;https:&#x2F;&#x2F;jagasantagostino.com&quot;&gt;Jaga Santagostino&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;robert.bio&quot;&gt;Robert Aboukhalil&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;bsky.app&#x2F;profile&#x2F;me.tverghis.space&quot;&gt;Tarun Verghis&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;tylerity.com&quot;&gt;Tyler Sparks&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Everyone who came to hang out and help out in the &lt;a href=&quot;https:&#x2F;&#x2F;www.twitch.tv&#x2F;samwhoo&quot;&gt;Twitch streams&lt;&#x2F;a&gt; when I
was building out the early versions of the Turing machine visualisations.&lt;&#x2F;li&gt;
&lt;li&gt;Everyone who supports my work on &lt;a href=&quot;https:&#x2F;&#x2F;patreon.com&#x2F;samwho&quot;&gt;Patreon&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Everyone who works on the tools used to build this post: TypeScript, Bun,
Two.js, Tween.js, Monaco, Peggy, Zed, and many other indirect dependencies.
We really do stand upon the shoulders of giants.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;mstdn.social&#x2F;@topo&quot;&gt;Cristián Rojo&lt;&#x2F;a&gt; for the Spanish translation of
this post.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;figure&gt;
  &lt;img src=&quot;&#x2F;images&#x2F;hut-8.png&quot; &#x2F;&gt;
  &lt;figcaption&gt;
    Hut 8, Bletchley Park, where Turing worked during World War II. It was in
    this hut that Alan worked with his team to break the German Naval Enigma
    code.
  &lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
</content>
            
        </entry>
    
    
        <entry xml:lang="en">
            <title>A Commitment to Art and Dogs</title>
            <published>2024-06-01T00:00:00+00:00</published>
            <updated>2024-06-01T00:00:00+00:00</updated>
            <author>
            <name>Unknown</name>
            </author>
            <link rel="alternate" href="https://old.samwho.dev/dogs/" type="text/html"/>
            <id>https://old.samwho.dev/dogs/</id>
            
            <content type="html">&lt;style&gt;
.dog-line {
  display: flex;
  flex-wrap: nowrap;
  flex-direction: row;
  width: 100%;
  height: 10rem;
  margin-top: 2rem;
  margin-bottom: 2rem;
}

.dog-line img {
  flex-grow: 1;
  height: auto;
  margin: 0;
  padding: 0;
  object-fit: contain;
}

.dog-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-gap: 1rem;
  margin-top: 2rem;
  margin-bottom: 2rem;
}
&lt;&#x2F;style&gt;
&lt;p&gt;Back in &lt;a href=&quot;&#x2F;memory-allocation&quot;&gt;Memory Allocation&lt;&#x2F;a&gt;, I introduced Haskie.&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;haskie&quot;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;haskie-triumphant-200px.png&quot; alt=&quot;A husky puppy looking triumphant&quot; &#x2F;&gt;
&lt;p&gt;
  Hello!
&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The idea behind Haskie was to create a character that could ask questions the
reader might have, and to &quot;soften&quot; the posts to make them feel less
intimidating. I got some feedback from people that Haskie was a bit too
childish, and didn&#x27;t feel like he belonged in posts about serious topics.
This feedback was in the minority, though, and most people liked him. So I kept
him and used him again in &lt;a href=&quot;&#x2F;hashing&quot;&gt;Hashing&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Having a proxy to the reader was useful. I could anticipate areas of confusion
and clear them up without creating enormous walls of text. I don&#x27;t like it
when the entire screen is filled with text, I like to break it up with images
and interactive elements. And now dogs.&lt;&#x2F;p&gt;
&lt;p&gt;Then in &lt;a href=&quot;&#x2F;bloom-filters&quot;&gt;Bloom Filters&lt;&#x2F;a&gt;, I found myself needing a
character to represent the &quot;adult in the room.&quot; If Haskie was my proxy to the
reader, this new character would serve as a proxy to all of the material I
learned from in the writing of the post. This is Sage.&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;haskie&quot;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;sage-happy-200px.png&quot; alt=&quot;A husky looking happy&quot; &#x2F;&gt;
&lt;p&gt;
  Well met!
&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I liked the idea of having a cast of characters, each with their own personality
and purpose. But I had a few problems.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;problems&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#problems&quot;&gt;#&lt;&#x2F;a&gt;
Problems&lt;&#x2F;h2&gt;
&lt;p&gt;Both Haskie and Sage, because I have no artistic ability, were generated by AI.
Back when I made them I was making no money from this blog, and I had no idea if
I was going to keep them around. I didn&#x27;t want to invest money in an idea that
could flop, so I didn&#x27;t feel bad about using AI to try it out.&lt;&#x2F;p&gt;
&lt;p&gt;Since then, however, I have been paid twice to write posts for companies, and I
know that I&#x27;m keeping the dogs. &lt;strong&gt;It wasn&#x27;t ethical to continue piggybacking on
AI&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;While ethics were the primary motivation, there were some other smaller problems
with the dogs:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The visual style of them, while I did like it, never felt like it fit
with the rest of my personal brand.&lt;&#x2F;li&gt;
&lt;li&gt;It was difficult to get AI to generate consistent dogs. You&#x27;ll notice
differences in coat colouration and features between variants of the same dog.&lt;&#x2F;li&gt;
&lt;li&gt;The AI generated images look bad at small sizes.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;So I worked with the wonderful &lt;a href=&quot;https:&#x2F;&#x2F;www.andycarolan.com&#x2F;&quot;&gt;Andy
Carolan&lt;&#x2F;a&gt; to create a new design for my dogs. A design that would be
consistent, fit with my brand, and look good at any size.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;haskie-sage-and-doe&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#haskie-sage-and-doe&quot;&gt;#&lt;&#x2F;a&gt;
Haskie, Sage, and Doe&lt;&#x2F;h2&gt;
&lt;div class=&quot;dog-line&quot;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;dogs&#x2F;haskie&#x2F;default.svg&quot; alt=&quot;A husky puppy called Haskie&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;dogs&#x2F;sage&#x2F;default.svg&quot; alt=&quot;A husky called Sage&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;dogs&#x2F;doe&#x2F;default.svg&quot; alt=&quot;A husky puppy called Doe&quot; &#x2F;&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;The redesigned dogs are consistent, use simple colours and shapes, and use the
SVG file format to look good at any size. Each variant clocks in at around
20kb, which is slightly larger than the small AI-generated images, but I&#x27;ll be
able to use them at any size.&lt;&#x2F;p&gt;
&lt;p&gt;Together the dogs represent a family unit: Sage as the dad, Haskie as the
youngest child, and Doe as his older sister.&lt;&#x2F;p&gt;
&lt;p&gt;They also come in a variety of poses, so I can use them to represent different
emotions or actions.&lt;&#x2F;p&gt;
&lt;div class=&quot;dog-grid&quot;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;dogs&#x2F;haskie&#x2F;bored.svg&quot; alt=&quot;A husky puppy called Haskie looking bored&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;dogs&#x2F;haskie&#x2F;concerned.svg&quot; alt=&quot;A husky puppy called Haskie looking concerned&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;dogs&#x2F;haskie&#x2F;confused.svg&quot; alt=&quot;A husky puppy called Haskie looking confused&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;dogs&#x2F;haskie&#x2F;triumphant.svg&quot; alt=&quot;A husky puppy called Haskie looking triumphant&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;dogs&#x2F;sage&#x2F;caution2.svg&quot; alt=&quot;A husky called Sage looking cautioning&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;dogs&#x2F;sage&#x2F;caution.svg&quot; alt=&quot;A husky called Sage looking cautioning&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;dogs&#x2F;sage&#x2F;despair.svg&quot; alt=&quot;A husky called Sage looking despaired&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;dogs&#x2F;sage&#x2F;proud.svg&quot; alt=&quot;A husky called Sage looking proud&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;dogs&#x2F;doe&#x2F;amazed.svg&quot; alt=&quot;A husky puppy called Doe looking amazed&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;dogs&#x2F;doe&#x2F;mischief.svg&quot; alt=&quot;A husky puppy called Doe looking mischievous&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;dogs&#x2F;doe&#x2F;protective.svg&quot; alt=&quot;A husky puppy called Doe looking protective&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;dogs&#x2F;doe&#x2F;proud.svg&quot; alt=&quot;A husky puppy called Doe looking proud&quot; &#x2F;&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;We were careful to make the dogs recognisable apart. They differ in colour, ear
shape, tail shape, and collar tag. Sage and Doe have further distinguishing
features: Sage with his glasses, and Doe with her bandana. Doe&#x27;s bandana uses
the same colours as the &lt;a
href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Transgender_flag&quot;&gt; transgender flag&lt;&#x2F;a&gt;,
to show my support for the trans community and as a nod to her identity.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;going-forward&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#going-forward&quot;&gt;#&lt;&#x2F;a&gt;
Going forward&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;m so happy with the new dogs, and plan to use them in my posts going forward.
I suspect I will, at some point, replace the dogs in my old posts as well.
I don&#x27;t plan to add any more characters, and I want to be careful to avoid
overusing them. I don&#x27;t want them to become a crutch, or to distract from the
content of the posts.&lt;&#x2F;p&gt;
&lt;p&gt;I also haven&#x27;t forgotten the many people that pointed out to me that you can&#x27;t
pet the dogs. I&#x27;m working on it.&lt;&#x2F;p&gt;
</content>
            
        </entry>
    
    
    
    
        <entry xml:lang="en">
            <title>Bloom Filters</title>
            <published>2024-02-19T00:00:00+00:00</published>
            <updated>2024-02-19T00:00:00+00:00</updated>
            <author>
            <name>Unknown</name>
            </author>
            <link rel="alternate" href="https://old.samwho.dev/bloom-filters/" type="text/html"/>
            <id>https://old.samwho.dev/bloom-filters/</id>
            
            <content type="html">&lt;style&gt;
.bf {
  width: 100%;
  height: 150px;
}

@media only screen and (min-width: 320px) and (max-width: 479px) {
  .bf {
    height: 200px;
  }
}

@media only screen and (min-width: 480px) and (max-width: 676px) {
  .bf {
    height: 200px;
  }
 }

@media only screen and (min-width: 677px) and (max-width: 991px) {
  .bf {
    height: 150px;
  }
}

form {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: stretch;
}

input {
    border: 1px solid rgb(119, 119, 119);
    padding: 0.25rem;
    border-radius: 0.25rem;
    height: 2em;
    line-height: 2em;
}

.aside {
  padding: 2rem;
  width: 100vw;
  position: relative;
  margin-left: -50vw;
  left: 50%;
  background-color: #eeeeee;

  display: flex;
  align-items: center;
  flex-direction: column;
}

.aside &gt; * {
  flex-grow: 1;
}

.aside p {
  padding-left: 1rem;
  padding-right: 1rem;
  max-width: 780px;
  font-style: italic;
  font-family: var(--heading-font);
  text-align: center;
}

&lt;&#x2F;style&gt;
&lt;noscript&gt;
  &lt;div class=aside&gt;
    &lt;p&gt;
    This page makes heavy use of JavaScript to visualise the concepts discussed.
    Viewing it without JavaScript will be a strange experience, as the text
    talks about the visualisations. I strongly recommend either enabling
    JavaScript, or not wasting your time.
    &lt;&#x2F;p&gt;
  &lt;&#x2F;div&gt;
&lt;&#x2F;noscript&gt;
&lt;p&gt;Everyone has a set of tools they use to solve problems. Growing this set helps
you to solve ever more difficult problems.  In this post, I&#x27;m going to teach you
about a tool you may not have heard of before. It&#x27;s a niche tool that won&#x27;t
apply to many problems, but when it does you&#x27;ll find it invaluable.  It&#x27;s called
a &quot;bloom filter.&quot;&lt;&#x2F;p&gt;
&lt;s-dog name=sage mode=warning&gt;
  &lt;b style=&quot;color: #d08770&quot;&gt;Before you continue!&lt;&#x2F;b&gt; This post
  assumes you know what a &lt;b&gt;hash function&lt;&#x2F;b&gt; is, and if you don&#x27;t it&#x27;s going
  to be tricky to understand. Sam has written a post about hash functions, and
  recommends that you &lt;b&gt;&lt;a href=&quot;&#x2F;hashing&quot;&gt;read this first&lt;&#x2F;a&gt;.&lt;&#x2F;b&gt;
&lt;&#x2F;s-dog&gt;
&lt;h3 id=&quot;what-bloom-filters-can-do&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#what-bloom-filters-can-do&quot;&gt;#&lt;&#x2F;a&gt;
What bloom filters can do&lt;&#x2F;h3&gt;
&lt;p&gt;Bloom filters are similar to the &lt;code&gt;Set&lt;&#x2F;code&gt; data structure. You can add items to
them, and check if an item is present. Here&#x27;s what it might look like to use
a bloom filter in JavaScript, using a made-up &lt;code&gt;BloomFilter&lt;&#x2F;code&gt; class:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;bf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;BloomFilter&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;bf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;add&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Ant&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;bf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;add&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Rhino&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;bf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;contains&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Ant&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;bf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;contains&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Rhino&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;While this looks almost identical to a &lt;code&gt;Set&lt;&#x2F;code&gt;, there are some key differences.
Bloom filters are what&#x27;s called a &lt;strong&gt;probabilistic data structure&lt;&#x2F;strong&gt;.  Where a
&lt;code&gt;Set&lt;&#x2F;code&gt; can give you a concrete &quot;yes&quot; or &quot;no&quot; answer when you call &lt;code&gt;contains&lt;&#x2F;code&gt;, a
bloom filter can&#x27;t. Bloom filters can give definite &quot;no&quot;s, but they can&#x27;t be
certain about &quot;yes.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;In the example above, when we ask &lt;code&gt;bf&lt;&#x2F;code&gt; if it contains &lt;code&gt;&quot;Ant&quot;&lt;&#x2F;code&gt; and &lt;code&gt;&quot;Rhino&quot;&lt;&#x2F;code&gt;, the
&lt;code&gt;true&lt;&#x2F;code&gt; that it returns isn&#x27;t a guarantee that they&#x27;re present. We know that
they&#x27;re present because we added them just a couple of lines before, but it
would be possible for this to happen:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;bf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;BloomFilter&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;bf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;add&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Ant&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;bf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;add&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Rhino&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;bf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;contains&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Fox&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We&#x27;ll demonstrate &lt;em&gt;why&lt;&#x2F;em&gt; over the course of this post. For now, we&#x27;ll say that
when bloom filters return &lt;code&gt;true&lt;&#x2F;code&gt; it doesn&#x27;t mean &quot;yes&quot;, it means &quot;maybe&quot;.  When
this happens and the item has never been added before, it&#x27;s called a
&lt;strong&gt;false-positive&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The opposite, claiming &quot;no&quot; when the answer is &quot;yes,&quot; is called a
&lt;strong&gt;false-negative&lt;&#x2F;strong&gt;. A bloom filter will &lt;em&gt;never&lt;&#x2F;em&gt; give a false-negative, and this
is what makes them useful.&lt;&#x2F;p&gt;
&lt;s-dog name=haskie mode=confused&gt;
  A data structure that lies to you?! How could that possibly be useful?
&lt;&#x2F;s-dog&gt;
&lt;p&gt;It&#x27;s not strictly lying, it&#x27;s just not giving you a definite answer. Let&#x27;s look
at an example where we can use this property to our advantage.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;when-bloom-filters-are-useful&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#when-bloom-filters-are-useful&quot;&gt;#&lt;&#x2F;a&gt;
When bloom filters are useful&lt;&#x2F;h3&gt;
&lt;p&gt;Imagine you&#x27;re building a web browser, and you want to protect users from
malicious links. You could build and maintain a list of all known malicious
links and check the list every time a user navigates the browser. If the link
they&#x27;re trying to visit is in the list, you warn the user that they might be
about to visit a malicious website.&lt;&#x2F;p&gt;
&lt;p&gt;If we assume there are, say, 1,000,000 malicious links on the Internet, and each
link is 20 characters long, then the list of malicious links would be 20MB in
size. This isn&#x27;t a huge amount of data, but it&#x27;s not small either. If you have
lots of users and want to keep this list up to date, the bandwidth could add up.&lt;&#x2F;p&gt;
&lt;p&gt;However, if you&#x27;re happy to accept being wrong 0.0001% of the time (1 in a
million), you could use a bloom filter which can store the same data in 3.59MB.
That&#x27;s an 82% reduction in size, and all it costs you is showing the user an
incorrect warning 1 in every million links visited. If you wanted to take it
even further, and you were happy to accept being wrong 0.1% of the time (1 in
1000), the bloom filter would only be 1.8MB.&lt;&#x2F;p&gt;
&lt;p&gt;This use-case isn&#x27;t hypothetical, either. Google Chrome used a bloom filter for
this exact purpose until 2012. If you were worried about showing a warning when
it wasn&#x27;t needed, you could always make an API that has the full list of
malicious links in a database. When the bloom filter says &quot;maybe,&quot; you would
then make an API call to check the full list to be sure. No more spurious
warnings, and the bloom filter would save you from having to call the API for
every link visited.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;how-bloom-filters-work&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#how-bloom-filters-work&quot;&gt;#&lt;&#x2F;a&gt;
How bloom filters work&lt;&#x2F;h3&gt;
&lt;p&gt;At its core, a bloom filter is an array of &lt;s-word&gt;bits&lt;&#x2F;s-word&gt;. When it is
created, all of the &lt;s-word&gt;bits&lt;&#x2F;s-word&gt; are set to 0. We&#x27;re going to represent
this as a grid of circles, with each circle representing 1 &lt;s-word&gt;bit&lt;&#x2F;s-word&gt;.
Our bloom filters in this post are all going to have 32 &lt;s-word&gt;bits&lt;&#x2F;s-word&gt; in
total.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;s-bloom-filter id=bf0 class=&quot;bf&quot; hashes=sha1,sha256,sha512 bits=32&gt;&lt;&#x2F;s-bloom-filter&gt;&lt;&#x2F;p&gt;
&lt;s-dog name=sam padding=false&gt;
  I&#x27;m experimenting with alternate colour palettes. If you find the above
  difficult to read, or just don&#x27;t like it, please try &lt;a
  href=&quot;?palette=tol#bf0&quot;&gt;this one&lt;&#x2F;a&gt; and let me know what you think.
  &lt;a href=&quot;?palette=wong#bf0&quot;&gt;Click here&lt;&#x2F;a&gt; to go back to normal.
&lt;&#x2F;s-dog&gt;
&lt;p&gt;To add an item to the bloom filter, we&#x27;re going to hash it with 3 different hash
functions, then use the 3 resulting values to set 3 &lt;s-word&gt;bits&lt;&#x2F;s-word&gt;. If
you&#x27;re not familiar with hashing, I recommend reading &lt;a href=&quot;&#x2F;hashing&quot;&gt;my post&lt;&#x2F;a&gt; about
it before continuing.&lt;&#x2F;p&gt;
&lt;p&gt;For this post I&#x27;m choosing to use 3 of the
&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Secure_Hash_Algorithms&quot;&gt;SHA&lt;&#x2F;a&gt; family of hash
functions: &lt;s-word&gt;sha1&lt;&#x2F;s-word&gt;, &lt;s-word&gt;sha256&lt;&#x2F;s-word&gt;, and
&lt;s-word&gt;sha512&lt;&#x2F;s-word&gt;. Here&#x27;s what our bloom filter looks like if we add the
value &quot;foo&quot; to it:&lt;&#x2F;p&gt;
&lt;s-bloom-filter id=bf1 class=&quot;bf&quot; hashes=sha1,sha256,sha512 bits=32&gt;
  &lt;add value=&quot;foo&quot;&gt;
&lt;&#x2F;s-bloom-filter&gt;
&lt;p&gt;The &lt;s-word&gt;bits&lt;&#x2F;s-word&gt; in positions &lt;s-bitlink bfid=bf1
highlight=true&gt;15&lt;&#x2F;s-bitlink&gt;, &lt;s-bitlink bfid=bf1&gt;16&lt;&#x2F;s-bitlink&gt; and &lt;s-bitlink
bfid=bf1&gt;27&lt;&#x2F;s-bitlink&gt; have been set. Other &lt;s-word&gt;bits&lt;&#x2F;s-word&gt;, e.g.
&lt;s-bitlink bfid=bf1&gt;1&lt;&#x2F;s-bitlink&gt; have not been set. You can hover or tap the
&lt;s-word&gt;bits&lt;&#x2F;s-word&gt; in this paragraph to highlight them in the visualisation.
We get to this state by taking the hash value of &quot;foo&quot; for each of our 3 hash
functions and modulo it by the number of &lt;s-word&gt;bits&lt;&#x2F;s-word&gt; in our bloom
filter. Modulo gets us the remainder when dividing by 32, so we get 27 with
&lt;s-word&gt;sha1&lt;&#x2F;s-word&gt;, 15 with &lt;s-word&gt;sha256&lt;&#x2F;s-word&gt; and 16 with
&lt;s-word&gt;sha512&lt;&#x2F;s-word&gt;. The table below shows what&#x27;s happening, and you can try
inputting your own values to see what &lt;s-word&gt;bits&lt;&#x2F;s-word&gt; they would set if
added.&lt;&#x2F;p&gt;
&lt;div style=&quot;display: flex; justify-content: center; margin-top: 1em&quot;&gt;
&lt;input
  type=&quot;text&quot;
  value=foo
  style=&quot;
    width: 20em;
    max-width: 100%;
    margin-left: 0.5em;
    margin-right: 0.5em;
  &quot;
  oninput=&quot;
    let hv = document.getElementById(&#x27;hv1&#x27;);
    hv.setAttribute(&#x27;value&#x27;, this.value);
  &quot;
&#x2F;&gt;
&lt;&#x2F;div&gt;
&lt;hash-values id=&quot;hv1&quot; bfid=bf1 value=foo mod=32&gt;&lt;&#x2F;hash-values&gt;
&lt;p&gt;Go ahead and &lt;s-word&gt;add&lt;&#x2F;s-word&gt; a few of your own values to our bloom filter
below and see what happens. There&#x27;s also a &lt;s-word&gt;check&lt;&#x2F;s-word&gt; button that
will tell you if a value is present within the bloom filter. A value is only
considered present if all of the &lt;s-word&gt;bits&lt;&#x2F;s-word&gt; checked are set. You can
start again by hitting the &lt;s-word&gt;clear&lt;&#x2F;s-word&gt; button.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;s-word-adder bfid=bf2&gt;&lt;&#x2F;s-word-adder&gt;
&lt;s-bloom-filter id=bf2 hashes=&quot;sha1,sha256,sha512&quot; bits=32 class=bf&gt;&lt;&#x2F;s-bloom-filter&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You might occasionally notice that only 2, or even 1, &lt;s-word&gt;bits&lt;&#x2F;s-word&gt; get
set. This happens when 2 or more of our hash functions produce the same value,
or we attempt to set a &lt;s-word&gt;bit&lt;&#x2F;s-word&gt; that has already been set. Taking
that a bit further, have a think about the implications of a bloom filter that
has every &lt;s-word&gt;bit&lt;&#x2F;s-word&gt; set.&lt;&#x2F;p&gt;
&lt;s-dog name=haskie mode=concerned&gt;
  Hmm... If every &lt;s-word&gt;bit&lt;&#x2F;s-word&gt; is set, then won&#x27;t the bloom filter
  claim it contains every item you check? That&#x27;s a false-positive every
  time!
&lt;&#x2F;s-dog&gt;
&lt;p&gt;Exactly right. A bloom filter with every &lt;s-word&gt;bit&lt;&#x2F;s-word&gt; set is equivalent
to a &lt;code&gt;Set&lt;&#x2F;code&gt; that always returns &lt;code&gt;true&lt;&#x2F;code&gt; for &lt;code&gt;contains&lt;&#x2F;code&gt;. It will claim to contain
everything you ask it about, even if that thing was never added.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;false-positive-rates&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#false-positive-rates&quot;&gt;#&lt;&#x2F;a&gt;
False-positive rates&lt;&#x2F;h2&gt;
&lt;p&gt;The rate of false-positives in our bloom filter will grow as the percentage of
set &lt;s-word&gt;bits&lt;&#x2F;s-word&gt; increases. Drag the slider below the graph to see how
the false-positive rate changes as the number of set &lt;s-word&gt;bits&lt;&#x2F;s-word&gt;
increases.&lt;&#x2F;p&gt;
&lt;s-graph id=graph1 style=&quot;width: 100%; aspect-ratio: 2&#x2F;1;&quot; drawupto=0&gt;
  &lt;axes&gt;
    &lt;x tics=0.2 ticformat=&quot;(tic * 100).toFixed(0) + &#x27;%&#x27;&quot; label=&quot;Bits set&quot; max=1&gt;
    &lt;y tics=0.2 ticformat=&quot;(tic * 100).toFixed(0) + &#x27;%&#x27;&quot; label=&quot;Chance of false-positive&quot; max=1&gt;
  &lt;&#x2F;axes&gt;
  &lt;lines&gt;
    &lt;line y=&quot;Math.pow(x, 3)&quot;&gt;
  &lt;&#x2F;lines&gt;
&lt;&#x2F;s-graph&gt;
&lt;s-slider
  value=0
  min=0
  max=1
  step=any
  onchange=&quot;
    document.getElementById(&#x27;graph1&#x27;).setAttribute(&#x27;drawupto&#x27;, e.target.value)
  &quot;&gt;
&lt;&#x2F;s-slider&gt;
&lt;p&gt;It grows slowly at first, but as we get closer to having all
&lt;s-word&gt;bits&lt;&#x2F;s-word&gt; set the rate increases. This is because we calculate the
false-positive rate as &lt;code&gt;x^3&lt;&#x2F;code&gt;, where &lt;code&gt;x&lt;&#x2F;code&gt; is the percentage of set
&lt;s-word&gt;bits&lt;&#x2F;s-word&gt; and &lt;code&gt;3&lt;&#x2F;code&gt; is the number of hash functions used. To give an
example of why we calculate it with this formula, imagine we have a bloom filter
with half of its bits set, &lt;code&gt;x = 0.5&lt;&#x2F;code&gt;.  If we assume that our hash function has
an equal chance of setting any of the bits, then the chance that all 3 hash
functions set a bit that is already set is &lt;code&gt;0.5 * 0.5 * 0.5&lt;&#x2F;code&gt;, or &lt;code&gt;x^3&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s have a look at the false-positive rate of bloom filters that use different
numbers of hash functions.&lt;&#x2F;p&gt;
&lt;s-graph id=graph2 style=&quot;width: 100%; aspect-ratio: 2&#x2F;1;&quot; drawupto=0&gt;
  &lt;legend position=top-left&gt;
  &lt;axes&gt;
    &lt;x tics=0.2 ticformat=&quot;(tic * 100).toFixed(0) + &#x27;%&#x27;&quot; label=&quot;Bits set&quot; max=1&gt;
    &lt;y tics=0.2 ticformat=&quot;(tic * 100).toFixed(0) + &#x27;%&#x27;&quot; label=&quot;Chance of false-positive&quot; max=1&gt;
  &lt;&#x2F;axes&gt;
  &lt;lines&gt;
    &lt;line y=&quot;Math.pow(x, 1)&quot; label=&quot;k=1&quot;&gt;
    &lt;line y=&quot;Math.pow(x, 2)&quot; label=&quot;k=2&quot;&gt;
    &lt;line y=&quot;Math.pow(x, 3)&quot; label=&quot;k=3&quot;&gt;
    &lt;line y=&quot;Math.pow(x, 4)&quot; label=&quot;k=4&quot;&gt;
    &lt;line y=&quot;Math.pow(x, 5)&quot; label=&quot;k=5&quot;&gt;
  &lt;&#x2F;lines&gt;
&lt;&#x2F;s-graph&gt;
&lt;s-slider
  value=0
  min=0
  max=1
  step=any
  onchange=&quot;
    document.getElementById(&#x27;graph2&#x27;).setAttribute(&#x27;drawupto&#x27;, e.target.value)
  &quot;&gt;
&lt;&#x2F;s-slider&gt;
&lt;s-dog name=haskie&gt;
  It looks like more hash functions we use, the better our false-positive rate
  is.  Doesn&#x27;t that mean we should always use lots of hash functions? Why don&#x27;t
  we use, like, 100?
&lt;&#x2F;s-dog&gt;
&lt;p&gt;The problem that using lots of hash functions introduces is that it makes the
bloom filter fill up faster. The more hash functions you use, the more
&lt;s-word&gt;bits&lt;&#x2F;s-word&gt; get set for each item you add. There&#x27;s also the cost of
hashing itself.  Hash functions aren&#x27;t free, and while the hash functions you&#x27;d
use in a bloom filter try to be as fast as possible, it&#x27;s still more expensive
to run 100 of them than it is to run 3.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s possible to calculate how full a bloom filter will be after inserting a
number of items, based on the number of hash functions used. The graph below
assumes a bloom filter with 1000 &lt;s-word&gt;bits&lt;&#x2F;s-word&gt;.&lt;&#x2F;p&gt;
&lt;s-graph id=graph3 style=&quot;width: 100%; aspect-ratio: 2&#x2F;1;&quot; drawupto=0&gt;
  &lt;legend position=top-left&gt;
  &lt;axes&gt;
    &lt;x tics=100 label=&quot;Items added&quot; max=1000&gt;
    &lt;y tics=100 label=&quot;Bits set&quot; max=1000&gt;
  &lt;&#x2F;axes&gt;
  &lt;lines&gt;
    &lt;line y=&quot;1000 * (1 - Math.pow(1 - 1&#x2F;1000, 5 * x))&quot; label=&quot;k=5&quot;&gt;
    &lt;line y=&quot;1000 * (1 - Math.pow(1 - 1&#x2F;1000, 4 * x))&quot; label=&quot;k=4&quot;&gt;
    &lt;line y=&quot;1000 * (1 - Math.pow(1 - 1&#x2F;1000, 3 * x))&quot; label=&quot;k=3&quot;&gt;
    &lt;line y=&quot;1000 * (1 - Math.pow(1 - 1&#x2F;1000, 2 * x))&quot; label=&quot;k=2&quot;&gt;
    &lt;line y=&quot;1000 * (1 - Math.pow(1 - 1&#x2F;1000, 1 * x))&quot; label=&quot;k=1&quot;&gt;
  &lt;&#x2F;lines&gt;
&lt;&#x2F;s-graph&gt;
&lt;s-slider
  value=0
  min=0
  max=1000
  step=any
  onchange=&quot;
    document.getElementById(&#x27;graph3&#x27;).setAttribute(&#x27;drawupto&#x27;, e.target.value)
  &quot;&gt;
&lt;&#x2F;s-slider&gt;
&lt;p&gt;The more hash functions we use, the faster we set all of the bits. You&#x27;ll notice that
the curve tails off as more items are added. This is because the more
&lt;s-word&gt;bits&lt;&#x2F;s-word&gt; that are set, the more likely it is that we&#x27;all attempt to
set a &lt;s-word&gt;bit&lt;&#x2F;s-word&gt; that has already been set.&lt;&#x2F;p&gt;
&lt;p&gt;In practice, 1000 &lt;s-word&gt;bits&lt;&#x2F;s-word&gt; is a very small bloom filter, occupying
only 125 bytes of memory. Modern computers have a lot of memory, so let&#x27;s crank this
up to 100,000 &lt;s-word&gt;bits&lt;&#x2F;s-word&gt; (12.5kB) and see what happens.&lt;&#x2F;p&gt;
&lt;s-graph id=graph4 style=&quot;width: 100%; aspect-ratio: 2&#x2F;1;&quot; drawupto=0&gt;
  &lt;legend position=top-left&gt;
  &lt;axes&gt;
    &lt;x tics=100 label=&quot;Items added&quot; max=1000&gt;
    &lt;y tics=10000 ticformat=&quot;(tic &#x2F; 1000).toFixed(0) + &#x27;k&#x27;&quot; label=&quot;Bits set&quot; max=100000&gt;
  &lt;&#x2F;axes&gt;
  &lt;lines&gt;
    &lt;line y=&quot;100000 * (1 - Math.pow(1 - 1&#x2F;100000, 5 * x))&quot; label=&quot;k=5&quot;&gt;
    &lt;line y=&quot;100000 * (1 - Math.pow(1 - 1&#x2F;100000, 4 * x))&quot; label=&quot;k=4&quot;&gt;
    &lt;line y=&quot;100000 * (1 - Math.pow(1 - 1&#x2F;100000, 3 * x))&quot; label=&quot;k=3&quot;&gt;
    &lt;line y=&quot;100000 * (1 - Math.pow(1 - 1&#x2F;100000, 2 * x))&quot; label=&quot;k=2&quot;&gt;
    &lt;line y=&quot;100000 * (1 - Math.pow(1 - 1&#x2F;100000, 1 * x))&quot; label=&quot;k=1&quot;&gt;
  &lt;&#x2F;lines&gt;
&lt;&#x2F;s-graph&gt;
&lt;s-slider
  value=0
  min=0
  max=1000
  step=any
  onchange=&quot;
    document.getElementById(&#x27;graph4&#x27;).setAttribute(&#x27;drawupto&#x27;, e.target.value)
  &quot;&gt;
&lt;&#x2F;s-slider&gt;
&lt;p&gt;The lines barely leave the bottom of the graph, meaning the bloom filter will
be very empty and the false-positive rate will be low. All this cost us was
12.5kB of memory, which is still a very small amount by 2024 standards.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tuning-a-bloom-filter&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#tuning-a-bloom-filter&quot;&gt;#&lt;&#x2F;a&gt;
Tuning a bloom filter&lt;&#x2F;h2&gt;
&lt;p&gt;Picking the correct number of hash functions and &lt;s-word&gt;bits&lt;&#x2F;s-word&gt; for a bloom
filter is a fine balance. Fortunately for us, if we know up-front how many
unique items we want to store, and what our desired false-positive rate is, we
can calculate the optimal number of hash functions, and the required number of
&lt;s-word&gt;bits&lt;&#x2F;s-word&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Bloom_filter&quot;&gt;bloom filter&lt;&#x2F;a&gt; page on Wikipedia
covers the mathematics involved, which I&#x27;m going to translate into JavaScript
functions for us to use. I want to stress that you don&#x27;t need to understand the
maths to use a bloom filter or read this post. I&#x27;m including the link to it only
for completeness.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;optimal-number-of-bits&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#optimal-number-of-bits&quot;&gt;#&lt;&#x2F;a&gt;
Optimal number of bits&lt;&#x2F;h3&gt;
&lt;p&gt;The following JavaScript function, which might look a bit scary but bear with
me, takes the number of items you want to store (&lt;code&gt;items&lt;&#x2F;code&gt;) and the desired
false-positive rate (&lt;code&gt;fpr&lt;&#x2F;code&gt;, where 1% == &lt;code&gt;0.01&lt;&#x2F;code&gt;), and returns how many
&lt;s-word&gt;bits&lt;&#x2F;s-word&gt; you will need to achieve that false-positive rate.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;bits&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;items&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;fpr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;n&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;items&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-constant z-math z-ts&quot;&gt;Math&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-math z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;fpr&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt;d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-constant z-math z-ts&quot;&gt;Math&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-math z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-constant z-math z-ts&quot;&gt;Math&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-math z-ts&quot;&gt;ceil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;d&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can see how this grows for a variety of &lt;code&gt;fpr&lt;&#x2F;code&gt; values in the graph below.&lt;&#x2F;p&gt;
&lt;s-graph id=graph5 style=&quot;width: 100%; aspect-ratio: 2&#x2F;1;&quot; drawupto=0&gt;
  &lt;legend position=top-left&gt;
  &lt;axes&gt;
    &lt;x tics=100 label=&quot;Items you plan to add&quot; max=1000&gt;
    &lt;y tics=1000 ticformat=&quot;(tic &#x2F; 1000).toFixed(0) + &#x27;k&#x27;&quot; label=&quot;Bits required&quot; max=10000&gt;
  &lt;&#x2F;axes&gt;
  &lt;lines&gt;
    &lt;line y=&quot;Math.ceil((-x * Math.log(0.01)) &#x2F; (Math.log(2) ** 2))&quot; label=&quot;fpr=0.01 (1%)&quot;&gt;
    &lt;line y=&quot;Math.ceil((-x * Math.log(0.05)) &#x2F; (Math.log(2) ** 2))&quot; label=&quot;fpr=0.05 (5%)&quot;&gt;
    &lt;line y=&quot;Math.ceil((-x * Math.log(0.10)) &#x2F; (Math.log(2) ** 2))&quot; label=&quot;fpr=0.1 (10%)&quot;&gt;
  &lt;&#x2F;lines&gt;
&lt;&#x2F;s-graph&gt;
&lt;s-slider
  value=0
  min=0
  max=1000
  step=any
  onchange=&quot;
    document.getElementById(&#x27;graph5&#x27;).setAttribute(&#x27;drawupto&#x27;, e.target.value)
  &quot;&gt;
&lt;&#x2F;s-slider&gt;
&lt;h3 id=&quot;optimal-number-of-hash-functions&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#optimal-number-of-hash-functions&quot;&gt;#&lt;&#x2F;a&gt;
Optimal number of hash functions&lt;&#x2F;h3&gt;
&lt;p&gt;After we&#x27;ve used the JavaScript above to calculate how many
&lt;s-word&gt;bits&lt;&#x2F;s-word&gt; we need, we can use the following function to calculate
the optimal number of hash functions to use:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;hashFunctions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;bits&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;items&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-constant z-math z-ts&quot;&gt;Math&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-math z-ts&quot;&gt;ceil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;bits&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;&#x2F;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;items&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-constant z-math z-ts&quot;&gt;Math&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-math z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Pause for a second here and have a think about how the number of hash functions
might grow based on the size of the bloom filter and the number of items you
expect to add. Do you think you&#x27;ll use more hash functions, or fewer, as the
bloom filter gets larger? What about as the number of items increases?&lt;&#x2F;p&gt;
&lt;s-graph id=graph6 style=&quot;width: 100%; aspect-ratio: 2&#x2F;1;&quot; drawupto=0&gt;
  &lt;legend position=top-left&gt;
  &lt;axes&gt;
    &lt;x tics=1000 ticformat=&quot;(tic &#x2F; 1000).toFixed(0) + &#x27;k&#x27;&quot; label=&quot;Bits in bloom filter&quot; max=10000&gt;
    &lt;y tics=1 label=&quot;Optimal hash functions&quot; max=10&gt;
  &lt;&#x2F;axes&gt;
  &lt;lines&gt;
    &lt;line y=&quot;Math.ceil((x &#x2F; 100) * Math.log(2))&quot; label=&quot;items = 100&quot;&gt;
    &lt;line y=&quot;Math.ceil((x &#x2F; 1000) * Math.log(2))&quot; label=&quot;items = 1000&quot;&gt;
    &lt;line y=&quot;Math.ceil((x &#x2F; 5000) * Math.log(2))&quot; label=&quot;items = 5000&quot;&gt;
  &lt;&#x2F;lines&gt;
&lt;&#x2F;s-graph&gt;
&lt;s-slider
  value=0
  min=0
  max=10000
  step=any
  onchange=&quot;
    document.getElementById(&#x27;graph6&#x27;).setAttribute(&#x27;drawupto&#x27;, e.target.value)
  &quot;&gt;
&lt;&#x2F;s-slider&gt;
&lt;p&gt;The more items you plan to add, the fewer hash functions you should use. Yet, a
larger bloom filter means you can use more hash functions. More hash functions
keep the false-positive rate lower for longer, but more items fills up the bloom
filter faster. It&#x27;s a complex balancing act, and I am thankful that
mathematicians have done the hard work of figuring it out for us.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;caution&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#caution&quot;&gt;#&lt;&#x2F;a&gt;
Caution&lt;&#x2F;h3&gt;
&lt;p&gt;While we can stand on the shoulders of giants and pick the optimal number of
&lt;s-word&gt;bits&lt;&#x2F;s-word&gt; and hash functions for our bloom filter, it&#x27;s important to
remember that these rely on you giving good estimates of the number of items you
expect to add, and choosing a false-positive rate that&#x27;s acceptable for your
use-case. These numbers might be difficult to come up with, and I recommend
erring on the side of caution. If you&#x27;re not sure, it&#x27;s likely better to use a
larger bloom filter than you think you need.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;removing-items-from-a-bloom-filter&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#removing-items-from-a-bloom-filter&quot;&gt;#&lt;&#x2F;a&gt;
Removing items from a bloom filter&lt;&#x2F;h2&gt;
&lt;p&gt;We&#x27;ve spent the whole post talking about adding things to a bloom filter, and
the optimal parameters to use. We haven&#x27;t spoken at all about removing items.&lt;&#x2F;p&gt;
&lt;p&gt;And that&#x27;s because you can&#x27;t!&lt;&#x2F;p&gt;
&lt;p&gt;In a bloom filter, we&#x27;re using &lt;s-word&gt;bits&lt;&#x2F;s-word&gt;, individual 1s and 0s, to
track the presence of items. If we were to remove an item by setting its
&lt;s-word&gt;bits&lt;&#x2F;s-word&gt; to 0, we might also be removing other items by accident.
There&#x27;s no way of knowing.&lt;&#x2F;p&gt;
&lt;p&gt;Click the buttons of the bloom filter below to see this in action. First we will
add &quot;foo&quot;, then &quot;baz&quot;, and then we will remove &quot;baz&quot;. Hit &quot;clear&quot; if you want
to start again.&lt;&#x2F;p&gt;
&lt;s-add-remove bfid=bf3&gt;
  &lt;add value=&quot;foo&quot;&gt;
  &lt;add value=&quot;baz&quot;&gt;
  &lt;remove value=&quot;baz&quot;&gt;
  &lt;clear&gt;
&lt;&#x2F;s-add-remove&gt;
&lt;s-bloom-filter id=bf3 hashes=&quot;sha1,sha256,sha512&quot; bits=32 class=bf&gt;&lt;&#x2F;s-bloom-filter&gt;
&lt;p&gt;The end result of this sequence is a bloom filter that doesn&#x27;t contain &quot;baz&quot;,
but doesn&#x27;t contain &quot;foo&quot; either. Because both &quot;foo&quot; and &quot;baz&quot; set
&lt;s-word&gt;bit&lt;&#x2F;s-word&gt; &lt;s-bitlink bfid=bf3&gt;27&lt;&#x2F;s-bitlink&gt;, we accidentally clobber
the presence of &quot;foo&quot; while removing &quot;baz&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Something else you might have noticed playing with the above example is that if
you add &quot;foo&quot; and then attempt to remove &quot;baz&quot; before having added it, nothing
happens. Even though &lt;s-bitlink bfid=bf3&gt;27&lt;&#x2F;s-bitlink&gt; is set,
&lt;s-word&gt;bits&lt;&#x2F;s-word&gt; &lt;s-bitlink bfid=bf3&gt;18&lt;&#x2F;s-bitlink&gt; and &lt;s-bitlink
bfid=bf3&gt;23&lt;&#x2F;s-bitlink&gt; are not, so the bloom filter cannot contain &quot;baz&quot;.
Because of this, it won&#x27;t unset &lt;s-bitlink bfid=bf3&gt;27&lt;&#x2F;s-bitlink&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;counting-bloom-filters&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#counting-bloom-filters&quot;&gt;#&lt;&#x2F;a&gt;
Counting bloom filters&lt;&#x2F;h3&gt;
&lt;p&gt;While you can&#x27;t remove items from a standard bloom filter, there are variants
that allow you to do so. One of these variants is called a &quot;counting bloom
filter,&quot; which uses an array of counters instead of bits to keep track of items.&lt;&#x2F;p&gt;
&lt;s-add-remove bfid=bf4&gt;
  &lt;add value=&quot;foo&quot;&gt;
  &lt;add value=&quot;baz&quot;&gt;
  &lt;remove value=&quot;baz&quot;&gt;
  &lt;clear&gt;
&lt;&#x2F;s-add-remove&gt;
&lt;s-bloom-filter id=bf4 counting=true hashes=&quot;sha1,sha256,sha512&quot; bits=32 class=bf&gt;&lt;&#x2F;s-bloom-filter&gt;
&lt;p&gt;Now when you go through the sequence, the end result is that the bloom filter
still contains &quot;foo.&quot; It solves the problem.&lt;&#x2F;p&gt;
&lt;p&gt;The trade-off, though, is that counters are bigger than &lt;s-word&gt;bits&lt;&#x2F;s-word&gt;.
With 4 bits per counter you can increment up to 15. With 8 bits per counter you
can increment up to 255. You&#x27;ll need to pick a counter size sufficient to never
reach the maximum value, otherwise you risk corrupting the bloom filter. Using
8x more memory than a standard bloom filter could be a big deal, especially if
you&#x27;re using a bloom filter to save memory in the first place. Think hard about
whether you really need to be able to remove items from your bloom filter.&lt;&#x2F;p&gt;
&lt;p&gt;Counting bloom filters also introduce the possibility of false-negatives, which
are impossible in standard bloom filters. Consider the following example.&lt;&#x2F;p&gt;
&lt;s-add-remove bfid=bf5&gt;
  &lt;add value=&quot;loved&quot;&gt;
  &lt;add value=&quot;your&quot;&gt;
  &lt;remove value=&quot;response&quot;&gt;
  &lt;clear&gt;
&lt;&#x2F;s-add-remove&gt;
&lt;s-bloom-filter id=bf5 counting=true hashes=&quot;sha1,sha256,sha512&quot; bits=32 class=bf&gt;&lt;&#x2F;s-bloom-filter&gt;
&lt;p&gt;Because &quot;loved&quot; and &quot;response&quot; both hash to the &lt;s-word&gt;bits&lt;&#x2F;s-word&gt;
&lt;s-bitlink bfid=bf5&gt;5&lt;&#x2F;s-bitlink&gt;, &lt;s-bitlink bfid=bf5&gt;22&lt;&#x2F;s-bitlink&gt;, and
&lt;s-bitlink bfid=bf5&gt;26&lt;&#x2F;s-bitlink&gt;, when we remove &quot;response&quot; we also remove &quot;loved&quot;. If
we write this as JavaScript the problem becomes more clear:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;bf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;CountingBloomFilter&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;bf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;add&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;loved&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;bf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;add&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;your&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;bf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;remove&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;response&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;bf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;contains&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;loved&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; false&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Even though we know for sure we&#x27;ve added &quot;loved&quot; in this snippet, the call to
&lt;code&gt;contains&lt;&#x2F;code&gt; will return &lt;code&gt;false&lt;&#x2F;code&gt;. This sort of false-negative can&#x27;t happen in a
standard bloom filter, and it removes one of the key benefits of using a bloom
filter in the first place: the guarantee of no false-negatives.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bloom-filters-in-the-real-world&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#bloom-filters-in-the-real-world&quot;&gt;#&lt;&#x2F;a&gt;
Bloom filters in the real-world&lt;&#x2F;h2&gt;
&lt;p&gt;Real-world users of bloom filters include &lt;a href=&quot;https:&#x2F;&#x2F;www.akamai.com&#x2F;&quot;&gt;Akamai&lt;&#x2F;a&gt;, who
use them to avoid caching web pages that are accessed once and never again. They
do this by storing all page accesses in a bloom filter, and only writing them
into cache if the bloom filter says they&#x27;ve been seen before. This does result
in some pages being cached on the first access, but that&#x27;s fine because it&#x27;s
still an improvement. It would be impractical for them to store all page
accesses in a &lt;code&gt;Set&lt;&#x2F;code&gt;, so they accept the small false-positive rate in favour of
the significantly smaller bloom filter. Akamai released a
&lt;a href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20210814193152&#x2F;https:&#x2F;&#x2F;www.akamai.com&#x2F;us&#x2F;en&#x2F;multimedia&#x2F;documents&#x2F;technical-publication&#x2F;algorithmic-nuggets-in-content-delivery-technical-publication.pdf&quot;&gt;paper&lt;&#x2F;a&gt;
about this that goes into the full details if you&#x27;re interested.&lt;&#x2F;p&gt;
&lt;p&gt;Google&#x27;s
&lt;a href=&quot;https:&#x2F;&#x2F;storage.googleapis.com&#x2F;pub-tools-public-publication-data&#x2F;pdf&#x2F;68a74a85e1662fe02ff3967497f31fda7f32225c.pdf&quot;&gt;BigTable&lt;&#x2F;a&gt;
is a distributed key-value store, and uses bloom filters internally to know what
keys are stored within. When a read request for a key comes in, a bloom filter
in memory is first checked to see if the key is in the database. If not,
BigTable can respond with &quot;not found&quot; without ever needing to read from disk.
Sometimes the bloom filter will say a key might be in the database when it isn&#x27;t,
but this is fine because when that happens a disk access will confirm the key in
fact isn&#x27;t in the database.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#conclusion&quot;&gt;#&lt;&#x2F;a&gt;
Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Bloom filters, while niche, can be a huge optimisation in the right situation.
They&#x27;re a wonderful application of hash functions, and a great example of making
a deliberate trade-off to achieve a specific goal.&lt;&#x2F;p&gt;
&lt;p&gt;Trade-offs, and combining simpler building blocks to create more complex,
purpose-built data structures, are present everywhere in software engineering.
Being able to spot where a data structure could net a big win can separate you
from the pack, and take your career to the next level.&lt;&#x2F;p&gt;
&lt;p&gt;I hope you&#x27;ve enjoyed this post, and that you find a way to apply bloom filters
to a problem you&#x27;re working on.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join the discussion on &lt;a href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=39439505&quot;&gt;Hacker News&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;lobste.rs&#x2F;s&#x2F;gwyglz&#x2F;visual_interactive_guide_bloom_filters&quot;&gt;Lobste.rs&lt;&#x2F;a&gt;!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;acknowledgements&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#acknowledgements&quot;&gt;#&lt;&#x2F;a&gt;
Acknowledgements&lt;&#x2F;h2&gt;
&lt;p&gt;Enormous thank you to my reviewers, without whom this post would be a shadow of
what you read today. In no particular order:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;rylon.dev&quot;&gt;rylon&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;indy.codes&quot;&gt;Indy&lt;&#x2F;a&gt;,
&lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;AaronKalair&quot;&gt;Aaron&lt;&#x2F;a&gt;, Sophie, &lt;a href=&quot;https:&#x2F;&#x2F;dvsj.in&quot;&gt;Davis&lt;&#x2F;a&gt;,
&lt;a href=&quot;https:&#x2F;&#x2F;eduardmoldovan.com&quot;&gt;ed&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mike12345567&quot;&gt;Michael
Drury&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;antonz.org&#x2F;&quot;&gt;Anton Zhiyanov&lt;&#x2F;a&gt;,
&lt;a href=&quot;https:&#x2F;&#x2F;appliedgo.net&#x2F;&quot;&gt;Christoph Berger&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;aptkingston&quot;&gt;Andrew Kingston&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;thattommyhall.com&quot;&gt;Tom Hall&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
            
        </entry>
    
    
    
    
    
    
        <entry xml:lang="en">
            <title>Hashing</title>
            <published>2023-05-24T00:00:00+00:00</published>
            <updated>2023-05-24T00:00:00+00:00</updated>
            <author>
            <name>Unknown</name>
            </author>
            <link rel="alternate" href="https://old.samwho.dev/hashing/" type="text/html"/>
            <id>https://old.samwho.dev/hashing/</id>
            
            <content type="html">&lt;style&gt;
  form {
    padding-top: 0.5em;
    padding-left: 0.5em;
    padding-right: 0.5em;
    display: flex;
    justify-content: center;
    gap: 0.3em;
  }

  form input[type=text] {
    flex: 4 1 auto;
    min-width: 0;
    border-radius: 0.3em;
    border: 1px solid #aaaaaa;
    padding: 0.3em;
  }

  form button {
    flex: 1 1 auto;
    max-width: 140px;
  }

  form button:disabled {
    opacity: 0.5 !important;
  }

  form button.add {
    background-color: #009E73;
    color: white;
    border: 0;
    border-radius: 0.3em;
    cursor: pointer;
  }

  form button.check {
    background-color: #56B4E9;
    color: white;
    border: 0;
    border-radius: 0.3em;
    cursor: pointer;
  }

  form button.clear {
    background-color: #D55E00;
    color: white;
    border: 0;
    border-radius: 0.3em;
    cursor: pointer;
  }

  .grid-2x2 {
    display: &quot;grid&quot;;
  }

  .grid {
    user-select: none;
    cursor: pointer;
    margin-top: 1rem;
    margin-bottom: 1rem;
    border: 1px solid #009E73;
    width: 100%;
    display: grid;
    grid-template-columns: repeat(8, 1fr);
    grid-template-rows: repeat(2, 1fr);
  }

  .grid-item {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1&#x2F;1;
  }

  .grid-active {
    background-color: #009E73;
    color: white;
  }

  .above-grid {
    display: flex;
    justify-content: center;
  }

  .hash-examples {
    padding-top: 0.5rem;
    padding-bottom: 0.5rem;
    margin: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  .hash-examples div {
    margin: auto;
  }

  .hash-examples code {
    display: block;
    white-space: pre;
    font-weight: bold;
  }

  .hash-examples p {
    font-size: 0.75rem;
    font-style: italic;
    text-align: center;
    font-family: var(--heading-font);
    width: 75%;
  }

  .blob {
    cursor: pointer;
    background: #CC79A7;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 1.5rem;
    color: white;
    border-radius: 50%;
    margin: 10px;
    height: 3rem;
    width: 3rem;
    min-width: 3rem;
    max-width: 3rem;

    box-shadow: 0 0 0 0 #CC79A7FF;
    transform: scale(1);
    animation: pulse 2s infinite;
  }

  @keyframes pulse {
    0% {
      transform: scale(0.85);
      box-shadow: 0 0 0 0 #CC79A77F;
    }

    70% {
      transform: scale(1);
      box-shadow: 0 0 0 1rem rgba(0, 0, 0, 0);
    }

    100% {
      transform: scale(0.85);
      box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
    }
  }

  .blob-click {
    cursor: default;
    animation: tick 1s linear;
    background: #009E73FF;
  }

  @keyframes tick {
    0% {
      transform: scale(1);
      box-shadow: 0 0 0 0 #009E73FF;
    }

    50% {
      box-shadow: 0 0 0 1rem #009E737F;
    }

    100% {
      box-shadow: 0 0 0 2rem #009E7300;
    }
  }

  .aside {
    padding: 2rem;
    width: 100vw;
    position: relative;
    margin-left: -50vw;
    left: 50%;
    background-color: #eeeeee;

    display: flex;
    align-items: center;
    flex-direction: column;
  }

  .aside &gt; * {
    flex-grow: 1;
  }

  .aside p {
    padding-left: 1rem;
    padding-right: 1rem;
    max-width: 780px;
    font-style: italic;
    font-family: var(--heading-font);
    text-align: center;
  }

  .pct25 {
    width: 100%;
    height: 200px;
  }

  .datasets th {
    text-align: left;
  }

  .datasets td {
    text-align: left;
  }

  .datasets {
    table-layout: fixed;
  }

&lt;&#x2F;style&gt;
&lt;noscript&gt;
  &lt;div class=aside&gt;
    &lt;p&gt;
    This page makes heavy use of JavaScript to visualise the concepts discussed.
    Viewing it without JavaScript will be a strange experience, as the text
    talks about the visualisations. I strongly recommend either enabling
    JavaScript, or not wasting your time.
    &lt;&#x2F;p&gt;
  &lt;&#x2F;div&gt;
&lt;&#x2F;noscript&gt;
&lt;p&gt;As a programmer, you use hash functions every day. They&#x27;re used in databases
to optimise queries, they&#x27;re used in data structures to make things faster,
they&#x27;re used in security to keep data safe. Almost every interaction you have
with technology will involve hash functions in one way or another.&lt;&#x2F;p&gt;
&lt;p&gt;Hash functions are foundational, and they are &lt;strong&gt;everywhere&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;But what &lt;em&gt;is&lt;&#x2F;em&gt; a hash function, and how do they work?&lt;&#x2F;p&gt;
&lt;p&gt;In this post, we&#x27;re going to demystify hash functions. We&#x27;re going to start by
looking at a simple hash function, then we&#x27;re going to learn how to test if a
hash function is good or not, and then we&#x27;re going to look at a real-world use
of hash functions: the hash map.&lt;&#x2F;p&gt;
&lt;script&gt;
  document.addEventListener(&quot;DOMContentLoaded&quot;, function () {
      var blob = document.querySelector(&quot;.blob&quot;);
      blob.addEventListener(&quot;click&quot;, function () {
          blob.classList.add(&quot;blob-click&quot;);
          blob.innerText = &quot;✓&quot;;
      });
  });
&lt;&#x2F;script&gt;
&lt;div class=aside&gt;
  &lt;div class=blob&gt;
  &lt;&#x2F;div&gt;
  &lt;p&gt;
    This article has visualisations that can be &lt;span class=&quot;purple
    bold&quot;&gt;clicked&lt;&#x2F;span&gt;.
  &lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;what-is-a-hash-function&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#what-is-a-hash-function&quot;&gt;#&lt;&#x2F;a&gt;
What &lt;em&gt;is&lt;&#x2F;em&gt; a hash function?&lt;&#x2F;h2&gt;
&lt;p&gt;Hash functions are functions that take an input, usually a string, and produce a
number. If you were to call a hash function multiple times with the same input,
it will always return the same number, and that number returned will always be
within a promised range. What that range is will depend on the hash function,
some use 32-bit integers (so 0 to 4 billion), others go much larger.&lt;&#x2F;p&gt;
&lt;p&gt;If we were to write a dummy hash function in JavaScript, it might look like
this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;hash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;input&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Even without knowing &lt;em&gt;how&lt;&#x2F;em&gt; hash functions are used, it&#x27;s probably no surprise
that this hash function is useless. Let&#x27;s see how we can measure how good a
hash function is, and after that we&#x27;ll do a deep dive on how they&#x27;re used
within hash maps.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-makes-a-hash-function-good&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#what-makes-a-hash-function-good&quot;&gt;#&lt;&#x2F;a&gt;
What makes a hash function good?&lt;&#x2F;h2&gt;
&lt;p&gt;Because &lt;code&gt;input&lt;&#x2F;code&gt; can be any string, but the number returned is within some
promised range, it&#x27;s possible that two different inputs can return the same
number. This is called a &quot;collision,&quot; and good hash functions try to minimise
how many collisions they produce.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s not possible to completely eliminate collisions, though. If we wrote a hash
function that returned a number in the range 0 to 7, and we gave it 9 unique
inputs, we&#x27;re guaranteed at least 1 collision.&lt;&#x2F;p&gt;
&lt;div class=&quot;hash-examples&quot;&gt;
  &lt;div&gt;
    &lt;code&gt;hash(&quot;to&quot;)         == 3&lt;&#x2F;code&gt;
    &lt;code&gt;hash(&quot;the&quot;)        == 2&lt;&#x2F;code&gt;
    &lt;code&gt;hash(&quot;café&quot;)       == 0&lt;&#x2F;code&gt;
    &lt;code&gt;hash(&quot;de&quot;)         == 6&lt;&#x2F;code&gt;
    &lt;code&gt;hash(&quot;versailles&quot;) == 4&lt;&#x2F;code&gt;
    &lt;code&gt;hash(&quot;for&quot;)        == 5&lt;&#x2F;code&gt;
    &lt;code&gt;hash(&quot;coffee&quot;)     == 0&lt;&#x2F;code&gt;
    &lt;code&gt;hash(&quot;we&quot;)         == 7&lt;&#x2F;code&gt;
    &lt;code&gt;hash(&quot;had&quot;)        == 1&lt;&#x2F;code&gt;
  &lt;&#x2F;div&gt;
  &lt;p&gt;
    Output values from a well-known hash function, modulo 8. No matter what 9
    values we pass, there are only 8 unique numbers and so collisions are
    inevitable.  The goal is to have as few as possible.
  &lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;To visualise collisions, I&#x27;m going to use a grid. Each square of the grid is
going to represent a number output by a hash function. Here&#x27;s an example 8x2
grid. &lt;span class=&quot;purple bold&quot;&gt;Click&lt;&#x2F;span&gt; on the grid to increment the
example hash output value and see how we map it to a grid square. See what
happens when you get a number larger than the number of grid squares.&lt;&#x2F;p&gt;
&lt;script&gt;
  document.addEventListener(&quot;DOMContentLoaded&quot;, () =&gt; {
    let grid = document.getElementById(&quot;first-grid&quot;);
    let hash = document.getElementById(&quot;grid-hash&quot;);
    let modulo = document.getElementById(&quot;grid-modulo&quot;);
    grid.addEventListener(&quot;click&quot;, (e) =&gt; {
      e.preventDefault();
      let number = parseInt(hash.innerText) + 1;
      hash.innerText = number.toString();
      modulo.innerText = (number % 16).toString();

      grid.querySelector(&quot;.grid-active&quot;).classList.remove(&quot;grid-active&quot;);
      grid.children[number % 16].classList.add(&quot;grid-active&quot;);
      return false;
    });
  });
&lt;&#x2F;script&gt;
&lt;div class=above-grid&gt;
  &lt;code style=&quot;color: #009E73; font-weight: bold;&quot;&gt;
    &lt;span id=&quot;grid-hash&quot;&gt;13&lt;&#x2F;span&gt; % 16 == &lt;span id=&quot;grid-modulo&quot;&gt;13&lt;&#x2F;span&gt;
  &lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;grid&quot; id=&quot;first-grid&quot;&gt;
  &lt;div class=&quot;grid-item&quot;&gt;0&lt;&#x2F;div&gt;
  &lt;div class=&quot;grid-item&quot;&gt;1&lt;&#x2F;div&gt;
  &lt;div class=&quot;grid-item&quot;&gt;2&lt;&#x2F;div&gt;
  &lt;div class=&quot;grid-item&quot;&gt;3&lt;&#x2F;div&gt;
  &lt;div class=&quot;grid-item&quot;&gt;4&lt;&#x2F;div&gt;
  &lt;div class=&quot;grid-item&quot;&gt;5&lt;&#x2F;div&gt;
  &lt;div class=&quot;grid-item&quot;&gt;6&lt;&#x2F;div&gt;
  &lt;div class=&quot;grid-item&quot;&gt;7&lt;&#x2F;div&gt;
  &lt;div class=&quot;grid-item&quot;&gt;8&lt;&#x2F;div&gt;
  &lt;div class=&quot;grid-item&quot;&gt;9&lt;&#x2F;div&gt;
  &lt;div class=&quot;grid-item&quot;&gt;10&lt;&#x2F;div&gt;
  &lt;div class=&quot;grid-item&quot;&gt;11&lt;&#x2F;div&gt;
  &lt;div class=&quot;grid-item&quot;&gt;12&lt;&#x2F;div&gt;
  &lt;div class=&quot;grid-item grid-active&quot;&gt;13&lt;&#x2F;div&gt;
  &lt;div class=&quot;grid-item&quot;&gt;14&lt;&#x2F;div&gt;
  &lt;div class=&quot;grid-item&quot;&gt;15&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Every time we hash a value, we&#x27;re going to make its corresponding square on the
grid a bit darker. The idea is to create an easy way to see how well a hash
function avoids collisions. What we&#x27;re looking for is a nice, even distribution.
We&#x27;ll know that the hash function isn&#x27;t good if we have clumps or patterns of
dark squares.&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;haskie&quot;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;haskie-confused-200px.png&quot; &#x2F;&gt;
&lt;p&gt;
  You said that when a hash function outputs the same value for 2 different
  inputs, that&#x27;s a collision. But if we have a hash function that outputs values
  in a big range, and we mapped those to a small grid, aren&#x27;t we going to create
  lots of collisions on the grid that aren&#x27;t actually collisions? On our 8x2
  grid, 1 and 17 both map to the 2nd square.
&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;This is a great observation. You&#x27;re absolutely right, we&#x27;re going to be creating
&quot;pseudo-collisions&quot; on our grid. It&#x27;s okay, though, because if the hash function
is good we will still see an even distribution. Incrementing every square by 100
is just as good a distribution as incrementing every square by 1. If we have a
bad hash function that collides a lot, that will still stand out. We&#x27;ll see
this shortly.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s take a larger grid and hash 1,000 randomly-generated strings. You can
&lt;span class=&quot;purple bold&quot;&gt;click&lt;&#x2F;span&gt; on the grid to hash a new set of random
inputs, and the grid will animate to show you each input being hashed and placed
on the grid.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;heat-map
  class=&quot;pct25&quot;
  iterations=1000
  blockSize=20
  valueFn=randomUUID
  hashFn=murmur3
  color=green&gt;
&lt;&#x2F;heat-map&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The values are nice and evenly distributed because we&#x27;re using a good,
well-known hash function called &lt;code class=&quot;green&quot;&gt;murmur3&lt;&#x2F;code&gt;. This hash
is widely used in the real-world because it has great distribution while also
being really, really fast.&lt;&#x2F;p&gt;
&lt;p&gt;What would our grid look like if we used a &lt;em&gt;bad&lt;&#x2F;em&gt; hash function?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-ts&quot;&gt;function&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-definition z-function z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;hash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;input&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;hash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-loop z-ts&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;c&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-of z-ts&quot;&gt;of&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;input&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;hash&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-compound z-ts&quot;&gt;+=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;charCodeAt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;hash&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;%&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-decimal z-ts&quot;&gt;1000000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This hash function loops through the string that we&#x27;re given and sums the
numeric values of each character. It then makes sure that the value is between 0
and 1000000 by using the modulus operator (&lt;code&gt;%&lt;&#x2F;code&gt;). Let&#x27;s call this hash function
&lt;code class=&quot;red&quot;&gt;stringSum&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Here it is on the grid. Reminder, this is 1,000 randomly generated strings that
we&#x27;re hashing.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;heat-map
  class=&quot;pct25&quot;
  iterations=1000
  blockSize=20
  valueFn=randomUUID
  hashFn=stringSum
  color=red&gt;
&lt;&#x2F;heat-map&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This doesn&#x27;t look all that different from &lt;code class=&quot;green&quot;&gt;murmur3&lt;&#x2F;code&gt;.
What gives?&lt;&#x2F;p&gt;
&lt;p&gt;The problem is that the strings we&#x27;re giving to be hashed are random. Let&#x27;s see
how each function performs when given input that is not random: the numbers from
1 to 1000 converted to strings.&lt;&#x2F;p&gt;
&lt;div style=&quot;display: flex; flex-wrap: wrap; gap: 0.5rem; justify-content: space-between; padding-top: 1rem; padding-bottom: 1rem&quot;&gt;
  &lt;heat-map
    style=&quot;flex-grow: 1; width: 40%; min-width: 200px; aspect-ratio: 2&#x2F;1;&quot;
    iterations=1000
    blockSize=10
    valueFn=intToStr
    hashFn=murmur3
    color=green&gt;
  &lt;&#x2F;heat-map&gt;
  &lt;heat-map
    style=&quot;flex-grow: 1; width: 40%; min-width: 200px; aspect-ratio: 2&#x2F;1;&quot;
    iterations=1000
    blockSize=10
    valueFn=intToStr
    hashFn=stringSum
    color=red&gt;
  &lt;&#x2F;heat-map&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Now the problem is more clear. When the input isn&#x27;t random, the output of &lt;code
class=&quot;red&quot;&gt;stringSum&lt;&#x2F;code&gt; forms a pattern. Our &lt;code
class=&quot;green&quot;&gt;murmur3&lt;&#x2F;code&gt; grid, however, looks the same as how it looked with
random values.&lt;&#x2F;p&gt;
&lt;p&gt;How about if we hash the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;powerlanguage&#x2F;word-lists&#x2F;blob&#x2F;master&#x2F;1000-most-common-words.txt&quot;&gt;top 1,000 most common English words&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;div style=&quot;display: flex; flex-wrap: wrap; gap: 0.5rem; justify-content: space-between; padding-top: 1rem; padding-bottom: 1rem&quot;&gt;
  &lt;heat-map
    style=&quot;flex-grow: 1; width: 40%; min-width: 200px; aspect-ratio: 2&#x2F;1;&quot;
    iterations=1000
    blockSize=10
    valueFn=commonWords
    hashFn=murmur3
    color=green&gt;
  &lt;&#x2F;heat-map&gt;
  &lt;heat-map
    style=&quot;flex-grow: 1; width: 40%; min-width: 200px; aspect-ratio: 2&#x2F;1;&quot;
    iterations=1000
    blockSize=10
    valueFn=commonWords
    hashFn=stringSum
    color=red&gt;
  &lt;&#x2F;heat-map&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;It&#x27;s more subtle, but we do see a pattern on the &lt;code class=&quot;bold
red&quot;&gt;stringSum&lt;&#x2F;code&gt; grid. As usual, &lt;code class=&quot;green bold&quot;&gt;murmur3&lt;&#x2F;code&gt;
looks the same as it always does.&lt;&#x2F;p&gt;
&lt;p&gt;This is the power of a good hash function: no matter the input,
the output is evenly distributed. Let&#x27;s talk about one more way to visualise
this and then talk about why it matters.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-avalanche-effect&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#the-avalanche-effect&quot;&gt;#&lt;&#x2F;a&gt;
The avalanche effect&lt;&#x2F;h3&gt;
&lt;p&gt;Another way hash functions get evaluated is on something called the &quot;avalanche
effect.&quot; This refers to how many bits in the output value change when just a
single bit of the input changes. To say that a hash function has a good
avalanche effect, a single bit flip in the input should result in an average of
50% the output bits flipping.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s this property that helps hash functions avoid forming patterns in the grid.
If small changes in the input result in small changes in the output, you get
patterns. Patterns indicate poor distribution, and a higher rate of collisions.&lt;&#x2F;p&gt;
&lt;p&gt;Below, we are visualising the avalanche effect by showing two 8-bit binary
numbers. The top number is the input value, and the bottom number is the &lt;code
class=&quot;green bold&quot;&gt;murmur3&lt;&#x2F;code&gt; output value. &lt;span class=&quot;purple
bold&quot;&gt;Click&lt;&#x2F;span&gt; on it to &lt;span class=&quot;purple bold&quot;&gt;flip a single bit&lt;&#x2F;span&gt;
in the input. Bits that change in the output will be &lt;span class=&quot;green
bold&quot;&gt;green&lt;&#x2F;span&gt;, bits that stay the same will be &lt;span class=&quot;red
bold&quot;&gt;red&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;avalanche-effect
  style=&quot;width: 100%; height: 200px;&quot;
  hashFn=&quot;murmur3&quot;&gt;
&lt;&#x2F;avalanche-effect&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;span class=&quot;green bold&quot;&gt;murmur3&lt;&#x2F;span&gt; does well, though you will notice that
sometimes fewer than 50% of the bits flip and sometimes more. This is okay,
provided that it is 50% on average.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s see how &lt;span class=&quot;bold red&quot;&gt;stringSum&lt;&#x2F;span&gt; performs.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;avalanche-effect
  style=&quot;width: 100%; height: 200px;&quot;
  hashFn=&quot;stringSum&quot;&gt;
&lt;&#x2F;avalanche-effect&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Well this is embarassing. The output is equal to the input, and so only a single
bit flips each time. This does make sense, because &lt;span class=&quot;bold
red&quot;&gt;stringSum&lt;&#x2F;span&gt; just sums the numeric value of each character in the
string. This example only hashes the equivalent of a single character, which
means the output will always be the same as the input.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-all-of-this-matters&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#why-all-of-this-matters&quot;&gt;#&lt;&#x2F;a&gt;
Why all of this matters&lt;&#x2F;h2&gt;
&lt;p&gt;We&#x27;ve taken the time to understand some of the ways to determine if a hash
function is good, but we&#x27;ve not spent any time talking about why it matters.
Let&#x27;s fix that by talking about hash maps.&lt;&#x2F;p&gt;
&lt;p&gt;To understand hash maps, we first must understand what a map is. A map is a data
structure that allows you to store key-value pairs. Here&#x27;s an example in
JavaScript:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;map&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Map&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;set&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;hello&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;world&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-support z-class z-console z-ts&quot;&gt;console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-console z-ts&quot;&gt;log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;hello&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here we take a key-value pair (&lt;code&gt;&quot;hello&quot;&lt;&#x2F;code&gt; → &lt;code&gt;&quot;world&quot;&lt;&#x2F;code&gt;) and store it in the map.
Then we print out the value associated with the key &lt;code&gt;&quot;hello&quot;&lt;&#x2F;code&gt;, which will be
&lt;code&gt;&quot;world&quot;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;A more fun real-world use-case would be to find anagrams. An anagram is when two
different words contain the same letters, for example &quot;antlers&quot; and &quot;rentals&quot;
or &quot;article&quot; and &quot;recital.&quot; If you have a list of words and you want to find
all of the anagrams, you can sort the letters in each word alphabetically and
use that as a key in a map.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;words&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;  &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;antlers&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;  &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;rentals&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;  &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;sternal&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;  &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;article&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;  &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;recital&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;  &lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;flamboyant&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;map&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-new z-expr z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new z-ts&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-ts&quot;&gt;Map&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-keyword z-control z-loop z-ts&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;word&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-of z-ts&quot;&gt;of&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;words&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;word&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;split&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;sort&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;join&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ts&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-ts&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;has&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;set&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-dom z-ts&quot;&gt;get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;word&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This code results in a map with the following structure:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json z-code&quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;aelnrst&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;antlers&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-sequence z-json&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;rentals&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-sequence z-json&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;sternal&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;aceilrt&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;article&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-sequence z-json&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;recital&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;aabflmnoty&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;flamboyant&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;implementing-our-own-simple-hash-map&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#implementing-our-own-simple-hash-map&quot;&gt;#&lt;&#x2F;a&gt;
Implementing our own simple hash map&lt;&#x2F;h3&gt;
&lt;p&gt;Hash maps are one of many map implementations, and there are many ways to
implement hash maps. The simplest way, and the way we&#x27;re going to demonstrate,
is to use a list of lists. The inner lists are often referred to as &quot;buckets&quot; in
the real-world, so that&#x27;s what we&#x27;ll call them here. A hash function is used on
the key to determine which bucket to store the key-value pair in, then the
key-value pair is added to that bucket.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s walk through a simple hash map implementation in JavaScript. We&#x27;re going
to go through it bottom-up, so we&#x27;ll see some utility methods before getting to
the &lt;code&gt;set&lt;&#x2F;code&gt; and &lt;code&gt;get&lt;&#x2F;code&gt; implementations.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-ts&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-ts&quot;&gt;HashMap&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-storage z-type z-ts&quot;&gt;constructor&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;bs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt; &lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We start off by creating a &lt;code&gt;HashMap&lt;&#x2F;code&gt; class with a constructor that sets up 3
buckets. We use 3 buckets and the short variable name &lt;code&gt;bs&lt;&#x2F;code&gt; so that this code
displays nicely on devices with smaller screens. In reality, you could have
however many buckets you want (and better variable names).&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-ts&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-ts&quot;&gt;HashMap&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;bucket&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;h&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;murmur3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;bs&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-array z-literal z-ts&quot;&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;h&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-ts&quot;&gt;%&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-property z-ts&quot;&gt;bs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-ts&quot;&gt;length&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-square z-ts&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;bucket&lt;&#x2F;code&gt; method uses &lt;code class=&quot;bold green&quot;&gt;murmur3&lt;&#x2F;code&gt; on the &lt;code&gt;key&lt;&#x2F;code&gt;
passed in to find a bucket to use. This is the only place in our hash map code
that a hash function is used.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-ts&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-ts&quot;&gt;HashMap&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;entry&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;bucket&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-loop z-ts&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;e&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-of z-ts&quot;&gt;of&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;bucket&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;key&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-ts&quot;&gt;===&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-null z-ts&quot;&gt;null&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;entry&lt;&#x2F;code&gt; method takes a &lt;code&gt;bucket&lt;&#x2F;code&gt; and a &lt;code&gt;key&lt;&#x2F;code&gt; and scans the bucket until it
finds an entry with the given key. If no entry is found, &lt;code&gt;null&lt;&#x2F;code&gt; is returned.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-ts&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-ts&quot;&gt;HashMap&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;set&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-parameter z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;bucket&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;e&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;entry&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-ts&quot;&gt;value&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-ts&quot;&gt;push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-objectliteral z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-object z-member z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;value&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;set&lt;&#x2F;code&gt; method is the first one we should recognise from our earlier
JavaScript &lt;code&gt;Map&lt;&#x2F;code&gt; examples. It takes a key-value pair and stores it in our hash
map. It does this by using the &lt;code&gt;bucket&lt;&#x2F;code&gt; and &lt;code&gt;entry&lt;&#x2F;code&gt; methods we created earlier.
If an entry is found, its value is overwritten. If no entry is found, the
key-value pair is added to the map. In JavaScript, &lt;code&gt;{ key, value }&lt;&#x2F;code&gt; is
shorthand for &lt;code&gt;{ key: key, value: value }&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript z-code&quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-class z-ts&quot;&gt;class&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-class z-ts&quot;&gt;HashMap&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-whitespace z-comment z-leading z-ts&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ts&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-ts&quot;&gt; ...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;  &lt;span class=&quot;z-meta z-definition z-method z-ts&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-parameters z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;bucket&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-meta z-var z-expr z-ts&quot;&gt;&lt;span class=&quot;z-storage z-type z-ts&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-var-single-variable z-expr z-ts&quot;&gt;&lt;span class=&quot;z-meta z-definition z-variable z-ts&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;e&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-ts&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-ts&quot;&gt;&lt;span class=&quot;z-variable z-language z-this z-ts&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-ts&quot;&gt;entry&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-comma z-ts&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-conditional z-ts&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-ts&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-brace z-round z-ts&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;      &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-object z-ts&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-ts&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-property z-dom z-ts&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-ts&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-null z-ts&quot;&gt;null&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-statement z-ts&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-meta z-method z-declaration z-ts&quot;&gt;&lt;span class=&quot;z-meta z-block z-ts&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ts&quot;&gt;&lt;span class=&quot;z-meta z-class z-ts&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-block z-ts&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;get&lt;&#x2F;code&gt; method is very similar to &lt;code&gt;set&lt;&#x2F;code&gt;. It uses &lt;code&gt;bucket&lt;&#x2F;code&gt; and &lt;code&gt;entry&lt;&#x2F;code&gt; to find
the entry related to the &lt;code&gt;key&lt;&#x2F;code&gt; passed in, just like &lt;code&gt;set&lt;&#x2F;code&gt; does. If an entry is
found, its &lt;code&gt;value&lt;&#x2F;code&gt; is returned. If one isn&#x27;t found, &lt;code&gt;null&lt;&#x2F;code&gt; is returned.&lt;&#x2F;p&gt;
&lt;p&gt;That was quite a lot of code. What you should take away from it is that our
hash map is a list of lists, and a hash function is used to know which of the
lists to store and retrieve a given key from.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s a visual representation of this hash map in action. &lt;span class=&quot;purple
bold&quot;&gt;Click&lt;&#x2F;span&gt; anywhere on the buckets to add a new key-value pair using our
&lt;code&gt;set&lt;&#x2F;code&gt; method. To keep the visualisation simple, if a bucket were to &quot;overflow&quot;,
the buckets are all reset.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;hash-map hashFn=murmur3 valueFn=intToStr&gt;&lt;&#x2F;hash-map&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Because we&#x27;re using &lt;code class=&quot;green bold&quot;&gt;murmur3&lt;&#x2F;code&gt; as our hash
function, you should see good distribution between the buckets. It&#x27;s expected
you&#x27;ll see &lt;em&gt;some&lt;&#x2F;em&gt; imbalance, but it should generally be quite even.&lt;&#x2F;p&gt;
&lt;p&gt;To get a value out of the hash map, we first hash the key to figure out which
bucket the value will be in. Then we have to compare the key we&#x27;re searching for
against all of the keys in the bucket.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s this search step that we minimise through hashing, and why &lt;code
class=&quot;bold green&quot;&gt;murmur3&lt;&#x2F;code&gt; is optimised for speed. The faster the hash
function, the faster we find the right bucket to search, the faster our hash
map is overall.&lt;&#x2F;p&gt;
&lt;p&gt;This is also why reducing collisions is so crucial. If we did decide to use that
dummy hash function from all the way at the start of this article, the one that
returns 0 all the time, we&#x27;ll put all of our key-value pairs into the first
bucket. Finding anything could mean we have to check all of the values in the
hash map. With a good hash function, with good distribution, we reduce the
amount of searching we have to do to 1&#x2F;N, where N is the number of buckets.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s see how &lt;code class=&quot;red bold&quot;&gt;stringSum&lt;&#x2F;code&gt; does.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;hash-map hashFn=stringSum valueFn=intToStr&gt;&lt;&#x2F;hash-map&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Interestingly, &lt;code class=&quot;bold red&quot;&gt;stringSum&lt;&#x2F;code&gt; seems to distribute
values quite well. You notice a pattern, but the overall distribution looks
good.&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;haskie&quot;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;haskie-triumphant-200px.png&quot; &#x2F;&gt;
&lt;p&gt;
  Finally! A win for &lt;code class=&quot;bold red&quot;&gt;stringSum&lt;&#x2F;code&gt;. I knew it would
  be good for something.
&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Not so fast, Haskie. We need to talk about a serious problem. The distribution
looks okay on these sequential numbers, but we&#x27;ve seen that &lt;code class=&quot;bold
red&quot;&gt;stringSum&lt;&#x2F;code&gt; doesn&#x27;t have a good avalanche effect. This doesn&#x27;t end
well.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;real-world-collisions&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#real-world-collisions&quot;&gt;#&lt;&#x2F;a&gt;
Real-world collisions&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s look at 2 real-world data sets: IP addresses and English words. What I&#x27;m
going to do is take 100,000,000 random IP addresses and &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dwyl&#x2F;english-words&quot;&gt;466,550 English
words&lt;&#x2F;a&gt;, hash all of them with both &lt;code class=&quot;bold green&quot;&gt;murmur3&lt;&#x2F;code&gt;
and &lt;code class=&quot;red bold&quot;&gt;stringSum&lt;&#x2F;code&gt;, and see how many collisions we get.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;b&gt;IP Addresses&lt;&#x2F;b&gt;&lt;&#x2F;p&gt;
&lt;table class=&quot;datasets&quot;&gt;
  &lt;th&gt;
  &lt;&#x2F;th&gt;
  &lt;th&gt;
    &lt;code class=&quot;bold green&quot;&gt;murmur3&lt;&#x2F;code&gt;
  &lt;&#x2F;th&gt;
  &lt;th&gt;
    &lt;code class=&quot;bold red&quot;&gt;stringSum&lt;&#x2F;code&gt;
  &lt;&#x2F;th&gt;
  &lt;tr&gt;
    &lt;td&gt;Collisions&lt;&#x2F;td&gt;
    &lt;td&gt;1,156,959&lt;&#x2F;td&gt;
    &lt;td&gt;99,999,566&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;&#x2F;td&gt;
    &lt;td&gt;1.157%&lt;&#x2F;td&gt;
    &lt;td&gt;99.999%&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
&lt;&#x2F;table&gt;
&lt;p&gt;&lt;b&gt;English words&lt;&#x2F;b&gt;&lt;&#x2F;p&gt;
&lt;table class=&quot;datasets&quot;&gt;
  &lt;th&gt;
  &lt;&#x2F;th&gt;
  &lt;th&gt;
    &lt;code class=&quot;bold green&quot;&gt;murmur3&lt;&#x2F;code&gt;
  &lt;&#x2F;th&gt;
  &lt;th&gt;
    &lt;code class=&quot;bold red&quot;&gt;stringSum&lt;&#x2F;code&gt;
  &lt;&#x2F;th&gt;
  &lt;tr&gt;
    &lt;td&gt;Collisions&lt;&#x2F;td&gt;
    &lt;td&gt;25&lt;&#x2F;td&gt;
    &lt;td&gt;464,220&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;&#x2F;td&gt;
    &lt;td&gt;0.005%&lt;&#x2F;td&gt;
    &lt;td&gt;99.5%&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
&lt;&#x2F;table&gt;
&lt;p&gt;When we use hash maps for real, we aren&#x27;t usually storing random values in them.
We can imagine counting the number of times we&#x27;ve seen an IP address in rate
limiting code for a server. Or code that counts the occurrences of words in
books throughout history to track their origin and popularity. &lt;code class=&quot;bold
red&quot;&gt;stringSum&lt;&#x2F;code&gt; sucks for these applications because of it&#x27;s extremely
high collision rate.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;manufactured-collisions&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#manufactured-collisions&quot;&gt;#&lt;&#x2F;a&gt;
Manufactured collisions&lt;&#x2F;h2&gt;
&lt;p&gt;Now it&#x27;s &lt;code class=&quot;bold green&quot;&gt;murmur3&lt;&#x2F;code&gt;&#x27;s turn for some bad news.
It&#x27;s not just collisions caused by similarity in the input we have to worry
about. Check this out.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;hash-map hashFn=murmur3 valueFn=murmur3Collisions&gt;&lt;&#x2F;hash-map&gt;&lt;&#x2F;p&gt;
&lt;p&gt;What&#x27;s happening here? Why do all of these jibberish strings hash to the same
number?&lt;&#x2F;p&gt;
&lt;p&gt;I hashed 141 trillion random strings to find values that hash to the number
&lt;code&gt;1228476406&lt;&#x2F;code&gt; when using &lt;code class=&quot;green bold&quot;&gt;murmur3&lt;&#x2F;code&gt;. Hash functions
have to always return the same output for a specific input, so it&#x27;s possible to
find collisions by brute force.&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;haskie&quot;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;haskie-concerned-200px.png&quot; &#x2F;&gt;
&lt;p&gt;
  I&#x27;m sorry, 141 &lt;b&gt;trillion&lt;&#x2F;b&gt;? Like... 141 and then 12 zeroes?
&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Yes, and it only took me 25 minutes. &lt;a href=&quot;https:&#x2F;&#x2F;computers-are-fast.github.io&#x2F;&quot;&gt;Computers are fast&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Bad actors having easy access to collisions can be devastating if your software
builds hash maps out of user input. Take HTTP headers, for example. An HTTP
request looks like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;GET &#x2F; HTTP&#x2F;1.1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Accept: *&#x2F;*
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Accept-Encoding: gzip, deflate
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Connection: keep-alive
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Host: google.com
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You don&#x27;t have to understand all of the words, just that the first line is the
path being requested and all of the other lines are headers. Headers are &lt;code&gt;Key: Value&lt;&#x2F;code&gt; pairs, so HTTP servers tend to use maps to store them. Nothing stops us
from passing any headers we want, so we can be really mean and pass headers we
know will cause collisions. This can significantly slow down the server.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;cryptanalysis.eu&#x2F;blog&#x2F;2011&#x2F;12&#x2F;28&#x2F;effective-dos-attacks-against-web-application-plattforms-hashdos&#x2F;&quot;&gt;This isn&#x27;t
theoretical, either&lt;&#x2F;a&gt;.
If you search &quot;HashDoS&quot; you&#x27;ll find a lot more examples of this. It was a really
big deal in the mid-2000s.&lt;&#x2F;p&gt;
&lt;p&gt;There are a few ways to mitigate this specific to HTTP servers: ignoring
jibberish header keys and limiting the number of headers you store, for
example. But modern hash functions like &lt;code class=&quot;bold green&quot;&gt;murmur3&lt;&#x2F;code&gt;
offer a more generalised solution: randomisation.&lt;&#x2F;p&gt;
&lt;p&gt;Earlier in this post we showed some examples of hash function implementations.
Those implementations took a single argument: &lt;code&gt;input&lt;&#x2F;code&gt;. Lots of modern hash
functions take a 2nd parameter: &lt;code&gt;seed&lt;&#x2F;code&gt; (sometimes called &lt;code&gt;salt&lt;&#x2F;code&gt;). In the case
of &lt;code class=&quot;green bold&quot;&gt;murmur3&lt;&#x2F;code&gt;, this seed is a number.&lt;&#x2F;p&gt;
&lt;p&gt;So far, we&#x27;ve been using 0 as the seed. Let&#x27;s see what happens with the
collisions I&#x27;ve collected when we use a seed of 1.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;hash-map hashFn=murmur3 valueFn=murmur3Collisions seed=1&gt;&lt;&#x2F;hash-map&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Just like that, 0 to 1, the collisions are gone. This is the purpose of the
seed: it randomises the output of the hash function in an unpredictable way.
How it achieves this is beyond the scope of this article, all hash functions do
this in their own way.&lt;&#x2F;p&gt;
&lt;p&gt;The hash function still returns the same output for the same input, it&#x27;s just
that the input is a combination of &lt;code&gt;input&lt;&#x2F;code&gt; and &lt;code&gt;seed&lt;&#x2F;code&gt;. Things that collide with
one seed shouldn&#x27;t collide when using another. Programming languages often
generate a random number to use as the seed when the process starts, so that
every time you run your program the seed is different. As a bad guy, not knowing
the seed, it is now impossible for me to reliably cause harm.&lt;&#x2F;p&gt;
&lt;p&gt;If you look closely in the above visualisation and the one before it, they&#x27;re
the same values being hashed but they produce different hash values. The
implication of this is that if you hash a value with one seed, and want to be
able to compare against it in the future, you need to make sure you use the same
seed.&lt;&#x2F;p&gt;
&lt;p&gt;Having different values for different seeds doesn&#x27;t affect the hash map
use-case, because hash maps only live for the duration the program is running.
Provided you use the same seed for the lifetime of the program, your hash maps
will continue to work just fine. If you ever store hash values outside of your
program, in a file for example, you need to be careful you know what seed has
been used.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;playground&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#playground&quot;&gt;#&lt;&#x2F;a&gt;
Playground&lt;&#x2F;h2&gt;
&lt;p&gt;As is tradition, I&#x27;ve made a playground for you to write your own hash functions
and see them visualised with the grids seen in this article. Click
&lt;a href=&quot;&#x2F;hashing-playground&#x2F;&quot;&gt;here&lt;&#x2F;a&gt; to try it!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#conclusion&quot;&gt;#&lt;&#x2F;a&gt;
Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;We&#x27;ve covered what a hash function is, some ways to measure how good it is,
what happens when it&#x27;s not good, and some of the ways they can be broken by
bad actors.&lt;&#x2F;p&gt;
&lt;p&gt;The universe of hash functions is a large one, and we&#x27;ve really only scratched
the surface in this post. We haven&#x27;t spoken about cryptographic vs
non-cryptographic hashing, we&#x27;ve touched on only 1 of the thousands of use-cases
for hash functions, and we haven&#x27;t talked about how exactly modern hash
functions actually work.&lt;&#x2F;p&gt;
&lt;p&gt;Some further reading I recommend if you&#x27;re really enthusiastic about this topic
and want to learn more:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rurban&#x2F;smhasher&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rurban&#x2F;smhasher&lt;&#x2F;a&gt; this repository is the gold standard
for testing how good hash functions are. They run a tonne of tests against
a wide number of hash functions and present the results in a big table. It
will be difficult to understand what all of the tests are for, but this is
where the state of the art of hash testing lives.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;djhworld.github.io&#x2F;hyperloglog&#x2F;&quot;&gt;https:&#x2F;&#x2F;djhworld.github.io&#x2F;hyperloglog&#x2F;&lt;&#x2F;a&gt; this is an interactive piece
on a data structure called HyperLogLog. It&#x27;s used to efficiently count the
number of unique elements in very, very large sets. It uses
hashing to do it in a really clever way.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;gperf&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;gperf&#x2F;&lt;&#x2F;a&gt; is a piece of software that, when given
the expected set of things you want to hash, can generate a &quot;perfect&quot; hash
function automatically.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Feel free to join the discussion on &lt;a href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=36401747&quot;&gt;Hacker News&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;acknowledgements&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#acknowledgements&quot;&gt;#&lt;&#x2F;a&gt;
Acknowledgements&lt;&#x2F;h2&gt;
&lt;p&gt;Thanks to everyone who read early drafts and provided invaluable feedback.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;delroth.net&#x2F;&quot;&gt;delroth&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;Manon_Lef&#x2F;&quot;&gt;Manon&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@AaronKalair&quot;&gt;Aaron&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;TheCoppinger&quot;&gt;Charlie&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;And everyone who helped me find &lt;code class=&quot;green bold&quot;&gt;murmur3&lt;&#x2F;code&gt; hash
collisions:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;indy.codes&#x2F;&quot;&gt;Indy&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@AaronKalair&quot;&gt;Aaron&lt;&#x2F;a&gt;, Max&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;patreon&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#patreon&quot;&gt;#&lt;&#x2F;a&gt;
Patreon&lt;&#x2F;h2&gt;
&lt;p&gt;After the success of &lt;a href=&quot;&#x2F;load-balancing&#x2F;&quot;&gt;Load Balancing&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;memory-allocation&#x2F;&quot;&gt;Memory
Allocation&lt;&#x2F;a&gt;, I have decided to set up a Patreon page:
&lt;a href=&quot;https:&#x2F;&#x2F;patreon.com&#x2F;samwho&quot;&gt;https:&#x2F;&#x2F;patreon.com&#x2F;samwho&lt;&#x2F;a&gt;. For all of these articles going forward, I am
going to post a Patreon-exclusive behind-the-scenes post talking about
decisions, difficulties, and lessons learned from each post. It will give you
a deep look in to how these articles evolve, and I&#x27;m really stoked about
the one I&#x27;ve written for this one.&lt;&#x2F;p&gt;
&lt;p&gt;If you enjoy my writing, and want to support it going forward, I&#x27;d really
appreciate you becoming a Patreon. ❤️&lt;&#x2F;p&gt;
</content>
            
        </entry>
    
    
    
    
    
    
        <entry xml:lang="en">
            <title>Memory Allocation</title>
            <published>2023-04-13T00:00:00+00:00</published>
            <updated>2023-04-13T00:00:00+00:00</updated>
            <author>
            <name>Unknown</name>
            </author>
            <link rel="alternate" href="https://old.samwho.dev/memory-allocation/" type="text/html"/>
            <id>https://old.samwho.dev/memory-allocation/</id>
            
            <content type="html">&lt;script src=&quot;&#x2F;js&#x2F;gsap&#x2F;gsap.min.js&quot;&gt;&lt;&#x2F;script&gt;
&lt;script src=&quot;&#x2F;js&#x2F;gsap&#x2F;PixiPlugin.min.js&quot;&gt;&lt;&#x2F;script&gt;
&lt;script type=&quot;module&quot; src=&quot;&#x2F;js&#x2F;memory-allocation.js&quot;&gt;&lt;&#x2F;script&gt;
&lt;style&gt;
.memory {
    width: 100%;
    margin-bottom: 1.5em;
    margin-top: 0.5em;
}
input[type=range]:focus {
  outline: none;
}
a[simulation] {
  cursor: pointer;
}
.size {
  color: #0072B2 !important;
  font-weight: bold;
}
.free {
  color: #009E73 !important;
  font-weight: bold;
}
.allocated {
  color: #D55E00 !important;
  font-weight: bold;
}
.usable-memory {
  color: #E69F00 !important;
  font-weight: bold;
}
&lt;&#x2F;style&gt;
&lt;p&gt;One thing that all programs on your computer have in common is a need for
memory. Programs need to be loaded from your hard drive into memory before they
can be run.  While running, the majority of what programs do is load values from
memory, do some computation on them, and then store the result back in memory.&lt;&#x2F;p&gt;
&lt;p&gt;In this post I&#x27;m going to introduce you to the basics of memory allocation.
Allocators exist because it&#x27;s not enough to have memory available, you need to
use it effectively. We will visually explore how simple allocators work. We&#x27;ll
see some of the problems that they try to solve, and some of the techniques used
to solve them. At the end of this post, you should know everything you need to
know to write your own allocator.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;malloc-and-free&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#malloc-and-free&quot;&gt;#&lt;&#x2F;a&gt;
&lt;code&gt;malloc&lt;&#x2F;code&gt; and &lt;code&gt;free&lt;&#x2F;code&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;To understand the job of a memory allocator, it&#x27;s essential to understand how
programs request and return memory.  &lt;code&gt;malloc&lt;&#x2F;code&gt; and &lt;code&gt;free&lt;&#x2F;code&gt; are functions that were
first introduced in a recognisable form in UNIX v7 in 1979(!). Let&#x27;s take a look
at a short C program demonstrating their use.&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;haskie&quot;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;haskie-concerned-200px.png&quot; &#x2F;&gt;
&lt;p&gt;
  Woah, hold on. I&#x27;ve never written any C code before. Will I still be able
  to follow along?
&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;If you have beginner-level familiarity with another language, e.g. JavaScript,
Python, or C#, you should have no problem following along. You don&#x27;t need to
understand every word, as long as you get the overall idea. This is the only
C code in the article, I promise.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; class=&quot;language-c z-code&quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-include z-c&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-include z-c&quot;&gt;#include&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-other z-lt-gt z-include z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;stdlib.h&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;  &lt;span class=&quot;z-storage z-type z-c&quot;&gt;void&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;ptr &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;malloc&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;free&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;ptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-return z-c&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the above program we ask for 4 bytes of memory by calling &lt;code&gt;malloc(4)&lt;&#x2F;code&gt;, we
store the value returned in a variable called &lt;code&gt;ptr&lt;&#x2F;code&gt;, then we indicate that we&#x27;re
done with the memory by calling &lt;code&gt;free(ptr)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;These two functions are how almost all programs manage the memory they use.
Even when you&#x27;re not writing C, the code that is executing your Java, Python,
Ruby, JavaScript, and so on make use of &lt;code&gt;malloc&lt;&#x2F;code&gt; and &lt;code&gt;free&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-memory&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#what-is-memory&quot;&gt;#&lt;&#x2F;a&gt;
What is memory?&lt;&#x2F;h2&gt;
&lt;p&gt;The smallest unit of memory that allocators work with is called a &quot;byte.&quot; A byte
can store any number between 0 and 255. You can think of memory as being a long
sequence of bytes. We&#x27;re going to represent this sequence as a grid of squares,
with each square representing a byte of memory.&lt;&#x2F;p&gt;
&lt;div class=&quot;memory&quot; bytes=&quot;32&quot; slider=false&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;In the C code from before, &lt;code&gt;malloc(4)&lt;&#x2F;code&gt; allocates 4 bytes of memory. We&#x27;re going
to represent memory that has been allocated as darker squares.&lt;&#x2F;p&gt;
&lt;div class=&quot;memory&quot; bytes=&quot;32&quot; slider=false&gt;
  &lt;malloc size=&quot;4&quot; addr=&quot;0x0&quot;&gt;&lt;&#x2F;malloc&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Then &lt;code&gt;free(ptr)&lt;&#x2F;code&gt; tells the allocator we&#x27;re done with that memory. It is returned
back to the pool of available memory.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s what 4 &lt;code&gt;malloc&lt;&#x2F;code&gt; calls followed by 4 &lt;code&gt;free&lt;&#x2F;code&gt; calls looks like.  You&#x27;ll
notice there&#x27;s now a slider.  Dragging the slider to the right advances time
forward, and dragging it left rewinds. You can also click anywhere on the grid
and then use the arrow keys on your keyboard, or you can use the left and right
buttons. The ticks along the slider represent calls to &lt;code&gt;malloc&lt;&#x2F;code&gt; and &lt;code&gt;free&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;div class=&quot;memory&quot; bytes=&quot;32&quot;&gt;
  &lt;malloc size=&quot;4&quot; addr=&quot;0x0&quot;&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc size=&quot;5&quot; addr=&quot;0x4&quot;&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc size=&quot;6&quot; addr=&quot;0x9&quot;&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc size=&quot;7&quot; addr=&quot;0xf&quot;&gt;&lt;&#x2F;malloc&gt;
  &lt;free addr=&quot;0x0&quot;&gt;&lt;&#x2F;free&gt;
  &lt;free addr=&quot;0x4&quot;&gt;&lt;&#x2F;free&gt;
  &lt;free addr=&quot;0x9&quot;&gt;&lt;&#x2F;free&gt;
  &lt;free addr=&quot;0xf&quot;&gt;&lt;&#x2F;free&gt;
&lt;&#x2F;div&gt;
&lt;blockquote class=&quot;haskie&quot;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;haskie-confused-200px.png&quot;&gt;
&lt;p&gt;
  Wait a sec... What is &lt;code&gt;malloc&lt;&#x2F;code&gt; actually returning as a value?
  What does it mean to &quot;give&quot; memory to a program?
&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;What &lt;code&gt;malloc&lt;&#x2F;code&gt; returns is called a &quot;pointer&quot; or a &quot;memory address.&quot; It&#x27;s a number
that identifies a byte in memory.  We typically write addresses in a form called
&quot;hexadecimal.&quot; Hexadecimal numbers are written with a &lt;code&gt;0x&lt;&#x2F;code&gt; prefix to distinguish
them from decimal numbers.  Move the slider below to see a comparison between
decimal numbers and hexadecimal numbers.&lt;&#x2F;p&gt;
&lt;div
  id=&quot;hexadecimal-demo&quot;
  style=&quot;display: flex; width: 100%; flex-direction: column;&quot;
&gt;
  &lt;div style=&quot;width: 100%; font-size: 2.5rem; display: flex; justify-content: center;&quot;&gt;
    &lt;code id=&quot;decimal&quot; style=&quot;min-width: 4rem; text-align: right&quot;&gt;0&lt;&#x2F;code&gt;
    &lt;code style=&quot;min-width: 5rem; text-align: center&quot;&gt;==&lt;&#x2F;code&gt;
    &lt;code id=&quot;hexadecimal&quot; style=&quot;min-width: 7rem; text-align: left&quot;&gt;0x0&lt;&#x2F;code&gt;
  &lt;&#x2F;div&gt;
  &lt;div&gt;
    &lt;input
      id=&quot;hexadecimal-slider&quot;
      type=&quot;range&quot;
      min=&quot;0&quot;
      max=&quot;32&quot;
      step=&quot;1&quot;
      value=&quot;0&quot;
      list=&quot;hexadecimal-demo-list&quot;
      style=&quot;width: 100%&quot; &#x2F;&gt;
    &lt;datalist id=&quot;hexadecimal-demo-list&quot;&gt;
      &lt;option value=1&gt;&lt;&#x2F;option&gt;
      &lt;option value=2&gt;&lt;&#x2F;option&gt;
      &lt;option value=3&gt;&lt;&#x2F;option&gt;
      &lt;option value=4&gt;&lt;&#x2F;option&gt;
      &lt;option value=5&gt;&lt;&#x2F;option&gt;
      &lt;option value=6&gt;&lt;&#x2F;option&gt;
      &lt;option value=7&gt;&lt;&#x2F;option&gt;
      &lt;option value=8&gt;&lt;&#x2F;option&gt;
      &lt;option value=9&gt;&lt;&#x2F;option&gt;
      &lt;option value=10&gt;&lt;&#x2F;option&gt;
      &lt;option value=11&gt;&lt;&#x2F;option&gt;
      &lt;option value=12&gt;&lt;&#x2F;option&gt;
      &lt;option value=13&gt;&lt;&#x2F;option&gt;
      &lt;option value=14&gt;&lt;&#x2F;option&gt;
      &lt;option value=15&gt;&lt;&#x2F;option&gt;
      &lt;option value=16&gt;&lt;&#x2F;option&gt;
      &lt;option value=17&gt;&lt;&#x2F;option&gt;
      &lt;option value=18&gt;&lt;&#x2F;option&gt;
      &lt;option value=19&gt;&lt;&#x2F;option&gt;
      &lt;option value=20&gt;&lt;&#x2F;option&gt;
      &lt;option value=21&gt;&lt;&#x2F;option&gt;
      &lt;option value=22&gt;&lt;&#x2F;option&gt;
      &lt;option value=23&gt;&lt;&#x2F;option&gt;
      &lt;option value=24&gt;&lt;&#x2F;option&gt;
      &lt;option value=25&gt;&lt;&#x2F;option&gt;
      &lt;option value=26&gt;&lt;&#x2F;option&gt;
      &lt;option value=27&gt;&lt;&#x2F;option&gt;
      &lt;option value=28&gt;&lt;&#x2F;option&gt;
      &lt;option value=29&gt;&lt;&#x2F;option&gt;
      &lt;option value=30&gt;&lt;&#x2F;option&gt;
      &lt;option value=31&gt;&lt;&#x2F;option&gt;
      &lt;option value=32&gt;&lt;&#x2F;option&gt;
    &lt;&#x2F;datalist&gt;
  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Here&#x27;s our familiar grid of memory. Each byte is annotated with its address in
hexadecimal form. For space reasons, I&#x27;ve omitted the &lt;code&gt;0x&lt;&#x2F;code&gt; prefix.&lt;&#x2F;p&gt;
&lt;div class=&quot;memory&quot; bytes=32 slider=false&gt;
  &lt;annotate type=&quot;text&quot; addr=0x0 text=0&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x1 text=1&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x2 text=2&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x3 text=3&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x4 text=4&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x5 text=5&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x6 text=6&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x7 text=7&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x8 text=8&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x9 text=9&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0xA text=A&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0xB text=B&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0xC text=C&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0xD text=D&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0xE text=E&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0xF text=F&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x10 text=10&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x11 text=11&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x12 text=12&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x13 text=13&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x14 text=14&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x15 text=15&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x16 text=16&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x17 text=17&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x18 text=18&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x19 text=19&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x1A text=1A&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x1B text=1B&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x1C text=1C&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x1D text=1D&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x1E text=1E&gt;&lt;&#x2F;annotate&gt;
  &lt;annotate type=&quot;text&quot; addr=0x1F text=1F&gt;&lt;&#x2F;annotate&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;The examples we use in this article pretend that your computer only has a very
small amount of memory, but in real life you have billions of bytes to work
with. Real addresses are much larger than what we&#x27;re using here, but the idea is
exactly the same. Memory addresses are numbers that refer to a specific byte in
memory.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-simplest-malloc&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#the-simplest-malloc&quot;&gt;#&lt;&#x2F;a&gt;
The simplest &lt;code&gt;malloc&lt;&#x2F;code&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The &quot;hello world&quot; of &lt;code&gt;malloc&lt;&#x2F;code&gt; implementations would hand out blocks of memory by
keeping track of where the previous block ended and starting the next block
right after.  Below we represent where the next block should start with a grey
square.&lt;&#x2F;p&gt;
&lt;div class=&quot;memory&quot; bytes=&quot;32&quot;&gt;
  &lt;allocator path=&quot;&#x2F;js&#x2F;allocators&#x2F;stack.js&quot;&gt;&lt;&#x2F;allocator&gt;
  &lt;malloc size=&quot;4&quot; addr=&quot;0x0&quot;&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc size=&quot;5&quot; addr=&quot;0x4&quot;&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc size=&quot;6&quot; addr=&quot;0x9&quot;&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc size=&quot;7&quot; addr=&quot;0xf&quot;&gt;&lt;&#x2F;malloc&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;You&#x27;ll notice no memory is &lt;code&gt;free&lt;&#x2F;code&gt;d. If we&#x27;re only keeping track of where the
next block should start, and we don&#x27;t know where previous blocks start or end,
&lt;code&gt;free&lt;&#x2F;code&gt; doesn&#x27;t have enough information to do anything. So it doesn&#x27;t. This is
called a &quot;memory leak&quot; because, once allocated, the memory can never be used
again.&lt;&#x2F;p&gt;
&lt;p&gt;Believe it or not, this isn&#x27;t a completely useless implementation.  For programs
that use a known amount of memory, this can be a very efficient strategy.  It&#x27;s
extremely fast and extremely simple. As a general-purpose memory allocator,
though, we can&#x27;t get away with having no &lt;code&gt;free&lt;&#x2F;code&gt; implementation.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-simplest-general-purpose-malloc&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#the-simplest-general-purpose-malloc&quot;&gt;#&lt;&#x2F;a&gt;
The simplest general-purpose &lt;code&gt;malloc&lt;&#x2F;code&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;In order to &lt;code&gt;free&lt;&#x2F;code&gt; memory, we need to keep better track of memory.  We can do
this by saving the address and size of all allocations, and the address and size
of blocks of free memory. We&#x27;ll call these an &quot;allocation list&quot; and a &quot;free
list&quot; respectively.&lt;&#x2F;p&gt;
&lt;div class=&quot;memory&quot; bytes=&quot;32&quot; slider=false&gt;
  &lt;allocator path=&quot;&#x2F;js&#x2F;allocators&#x2F;freelist.js&quot;&gt;
    &lt;options coalesce=false&gt;&lt;&#x2F;options&gt;
  &lt;&#x2F;allocator&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;We&#x27;re representing free list entries as 2 grey squares linked together with a
line. You can imagine this entry being represented in code as &lt;code&gt;address=0&lt;&#x2F;code&gt; and
&lt;code&gt;size=32&lt;&#x2F;code&gt;.  When our program starts, all of memory is marked as free. When
&lt;code&gt;malloc&lt;&#x2F;code&gt; is called, we loop through our free list until we find a block large
enough to accommodate it. When we find one, we save the address and size of the
allocation in our allocation list, and shrink the free list entry accordingly.&lt;&#x2F;p&gt;
&lt;div class=&quot;memory&quot; bytes=&quot;32&quot; slider=false&gt;
  &lt;allocator path=&quot;&#x2F;js&#x2F;allocators&#x2F;freelist.js&quot;&gt;
    &lt;options coalesce=false&gt;&lt;&#x2F;options&gt;
  &lt;&#x2F;allocator&gt;
  &lt;malloc id=1 size=4&gt;&lt;&#x2F;malloc&gt;
&lt;&#x2F;div&gt;
&lt;blockquote class=&quot;haskie&quot;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;haskie-confused-200px.png&quot;&gt;
&lt;p&gt;
  Where do we save allocations and free list entries? Aren&#x27;t we pretending our
  computer only has 32 bytes of memory?
&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;You caught me. One of the benefits of being a memory allocator is that you&#x27;re in
charge of memory. You could store your allocation&#x2F;free list in a reserved area
that&#x27;s just for you. Or you could store it inline, in a few bytes immediately
preceding each allocation.  For now, assume we have reserved some unseen memory
for ourselves and we&#x27;re using it to store our allocation and free lists.&lt;&#x2F;p&gt;
&lt;p&gt;So what about &lt;code&gt;free&lt;&#x2F;code&gt;? Because we&#x27;ve saved the address and size of the allocation
in our allocation list, we can search that list and move the allocation back in
to the free list. Without the size information, we wouldn&#x27;t be able to do this.&lt;&#x2F;p&gt;
&lt;div class=&quot;memory&quot; bytes=&quot;32&quot;&gt;
  &lt;allocator path=&quot;&#x2F;js&#x2F;allocators&#x2F;freelist.js&quot;&gt;
    &lt;options coalesce=false&gt;&lt;&#x2F;options&gt;
  &lt;&#x2F;allocator&gt;
  &lt;malloc id=1 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;free id=1&gt;&lt;&#x2F;free&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Our free list now has 2 entries. This might look harmless, but actually
represents a significant problem. Let&#x27;s see that problem in action.&lt;&#x2F;p&gt;
&lt;div class=&quot;memory&quot; bytes=&quot;32&quot;&gt;
  &lt;allocator path=&quot;&#x2F;js&#x2F;allocators&#x2F;freelist.js&quot;&gt;
    &lt;options coalesce=false&gt;&lt;&#x2F;options&gt;
  &lt;&#x2F;allocator&gt;
  &lt;malloc id=1 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=2 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=3 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=4 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=5 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=6 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=7 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=8 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;free id=1&gt;&lt;&#x2F;free&gt;
  &lt;free id=2&gt;&lt;&#x2F;free&gt;
  &lt;free id=3&gt;&lt;&#x2F;free&gt;
  &lt;free id=4&gt;&lt;&#x2F;free&gt;
  &lt;free id=5&gt;&lt;&#x2F;free&gt;
  &lt;free id=6&gt;&lt;&#x2F;free&gt;
  &lt;free id=7&gt;&lt;&#x2F;free&gt;
  &lt;free id=8&gt;&lt;&#x2F;free&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;We allocated 8 blocks of memory, each 4 bytes in size. Then we &lt;code&gt;free&lt;&#x2F;code&gt;d them all,
resulting in 8 free list entries.  The problem we have now is that if we tried
to do a &lt;code&gt;malloc(8)&lt;&#x2F;code&gt;, there are no items in our free list that can hold 8 bytes
and the &lt;code&gt;malloc(8)&lt;&#x2F;code&gt; will fail.&lt;&#x2F;p&gt;
&lt;p&gt;To solve this, we need to do a bit more work. When we &lt;code&gt;free&lt;&#x2F;code&gt; memory, we should
make sure that if the block we return to the free list is next to any other
free blocks, we combine them together. This is called &quot;coalescing.&quot;&lt;&#x2F;p&gt;
&lt;div class=&quot;memory&quot; bytes=&quot;32&quot;&gt;
  &lt;allocator path=&quot;&#x2F;js&#x2F;allocators&#x2F;freelist.js&quot;&gt;
    &lt;options coalesce=true&gt;
  &lt;&#x2F;allocator&gt;
  &lt;malloc id=1 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=2 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=3 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=4 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=5 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=6 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=7 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=8 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;free id=1&gt;&lt;&#x2F;free&gt;
  &lt;free id=2&gt;&lt;&#x2F;free&gt;
  &lt;free id=3&gt;&lt;&#x2F;free&gt;
  &lt;free id=4&gt;&lt;&#x2F;free&gt;
  &lt;free id=5&gt;&lt;&#x2F;free&gt;
  &lt;free id=6&gt;&lt;&#x2F;free&gt;
  &lt;free id=7&gt;&lt;&#x2F;free&gt;
  &lt;free id=8&gt;&lt;&#x2F;free&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Much better.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fragmentation&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#fragmentation&quot;&gt;#&lt;&#x2F;a&gt;
Fragmentation&lt;&#x2F;h2&gt;
&lt;p&gt;A perfectly coalesced free list doesn&#x27;t solve all of our problems. The following
example shows a longer sequence of allocations. Have a look at the state memory
is in at the end.&lt;&#x2F;p&gt;
&lt;div class=&quot;memory&quot; bytes=&quot;32&quot;&gt;
  &lt;allocator path=&quot;&#x2F;js&#x2F;allocators&#x2F;freelist.js&quot;&gt;
    &lt;options coalesce=true&gt;
  &lt;&#x2F;allocator&gt;
  &lt;malloc id=1 size=1&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=2 size=2&gt;&lt;&#x2F;malloc&gt;
  &lt;free id=1&gt;&lt;&#x2F;free&gt;
  &lt;malloc id=3 size=2&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=4 size=3&gt;&lt;&#x2F;malloc&gt;
  &lt;free id=3&gt;&lt;&#x2F;free&gt;
  &lt;malloc id=5 size=3&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=6 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;free id=5&gt;&lt;&#x2F;free&gt;
  &lt;malloc id=7 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=8 size=5&gt;&lt;&#x2F;malloc&gt;
  &lt;free id=7&gt;&lt;&#x2F;free&gt;
  &lt;free id=2&gt;&lt;&#x2F;free&gt;
  &lt;free id=4&gt;&lt;&#x2F;free&gt;
  &lt;malloc id=9 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=10 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=11 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=12 size=5&gt;&lt;&#x2F;malloc&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;We end this sequence with 6 of our 32 bytes free, but they&#x27;re split into 2
blocks of 3 bytes. If we had to service a &lt;code&gt;malloc(6)&lt;&#x2F;code&gt;, while we have enough free
memory in theory, we wouldn&#x27;t be able to.  This is called &quot;fragmentation.&quot;&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;haskie&quot;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;haskie-confused-200px.png&quot; &#x2F;&gt;
&lt;p&gt;
  Couldn&#x27;t we rearrange the memory to get a block of 6 contiguous bytes? Some
  sort of defragmentation process?
&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Sadly not. Remember earlier we talked about how the return value of &lt;code&gt;malloc&lt;&#x2F;code&gt; is
the address of a byte in memory? Moving allocations won&#x27;t change the pointers we
have already returned from &lt;code&gt;malloc&lt;&#x2F;code&gt;. We would change the value those pointers
are pointed at, effectively breaking them. This is one of the downsides of the
&lt;code&gt;malloc&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;free&lt;&#x2F;code&gt; API.&lt;&#x2F;p&gt;
&lt;p&gt;If we can&#x27;t move allocations after creating them, we need to be more careful
about where we put them to begin with.&lt;&#x2F;p&gt;
&lt;p&gt;One way to combat fragmentation is, confusingly, to overallocate.  If we always
allocate a minimum of 4 bytes, even when the request is for 1 byte, watch what
happens. This is the exact same sequence of allocations as above.&lt;&#x2F;p&gt;
&lt;div class=&quot;memory&quot; bytes=&quot;32&quot;&gt;
  &lt;allocator path=&quot;&#x2F;js&#x2F;allocators&#x2F;freelist.js&quot;&gt;
    &lt;options coalesce=true minsize=4&gt;
  &lt;&#x2F;allocator&gt;
  &lt;malloc id=1 size=1&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=2 size=2&gt;&lt;&#x2F;malloc&gt;
  &lt;free id=1&gt;&lt;&#x2F;free&gt;
  &lt;malloc id=3 size=2&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=4 size=3&gt;&lt;&#x2F;malloc&gt;
  &lt;free id=3&gt;&lt;&#x2F;free&gt;
  &lt;malloc id=5 size=3&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=6 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;free id=5&gt;&lt;&#x2F;free&gt;
  &lt;malloc id=7 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=8 size=5&gt;&lt;&#x2F;malloc&gt;
  &lt;free id=7&gt;&lt;&#x2F;free&gt;
  &lt;free id=2&gt;&lt;&#x2F;free&gt;
  &lt;free id=4&gt;&lt;&#x2F;free&gt;
  &lt;malloc id=9 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=10 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=11 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=12 size=5&gt;&lt;&#x2F;malloc&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Now we can service a &lt;code&gt;malloc(6)&lt;&#x2F;code&gt;. It&#x27;s worth keeping in mind that this is just
one example. Programs will call &lt;code&gt;malloc&lt;&#x2F;code&gt; and &lt;code&gt;free&lt;&#x2F;code&gt; in very different patterns
depending on what they do, which makes it challenging to design an allocator
that always performs well.&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;haskie&quot;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;haskie-confused-200px.png&quot; &#x2F;&gt;
&lt;p&gt;
  After the first &lt;code&gt;malloc&lt;&#x2F;code&gt;, the start of the free list seems to fall
  out of sync with allocated memory. Is that a bug in the visualisation?
&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;No, that&#x27;s a side-effect of overallocating.  The visualisation shows &quot;true&quot;
memory use, whereas the free list is updated from the allocator&#x27;s perspective.
So when the first &lt;code&gt;malloc&lt;&#x2F;code&gt; happens, 1 byte of memory is allocated but the free
list entry is moved forward 4 bytes. We trade some wasted space in return for
less fragmentation.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s worth noting that this unused space that results from overallocation is
another form of fragmentation. It&#x27;s memory that cannot be used until the
allocation that created it is freed. As a result, we wouldn&#x27;t want to go too
wild with overallocation. If our program only ever allocated 1 byte at a time,
for example, we&#x27;d be wasting 75% of all memory.&lt;&#x2F;p&gt;
&lt;p&gt;Another way to combat fragmentation is to segment memory into a space for small
allocations and a space for big ones. In this next visualisation we start with
two free lists. The lighter grey one is for allocations 3 bytes or smaller,
and the darker grey one is for allocations 4 bytes or larger. Again, this is
the exact same sequence of allocations as before.&lt;&#x2F;p&gt;
&lt;div id=&quot;segmented-1&quot; class=&quot;memory&quot; bytes=32&gt;
  &lt;allocator path=&quot;&#x2F;js&#x2F;allocators&#x2F;segmented-freelist.js&quot;&gt;
    &lt;options
      coalesce=true
      smallfreelistthreshold=3
      smallfreelistsize=6&gt;
    &lt;&#x2F;options&gt;
  &lt;&#x2F;allocator&gt;
  &lt;malloc id=1 size=1&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=2 size=2&gt;&lt;&#x2F;malloc&gt;
  &lt;free id=1&gt;&lt;&#x2F;free&gt;
  &lt;malloc id=3 size=2&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=4 size=3&gt;&lt;&#x2F;malloc&gt;
  &lt;free id=3&gt;&lt;&#x2F;free&gt;
  &lt;malloc id=5 size=3&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=6 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;free id=5&gt;&lt;&#x2F;free&gt;
  &lt;malloc id=7 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=8 size=5&gt;&lt;&#x2F;malloc&gt;
  &lt;free id=7&gt;&lt;&#x2F;free&gt;
  &lt;free id=2&gt;&lt;&#x2F;free&gt;
  &lt;free id=4&gt;&lt;&#x2F;free&gt;
  &lt;malloc id=9 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=10 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=11 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=12 size=5&gt;&lt;&#x2F;malloc&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Nice! This also reduces fragmentation. If we&#x27;re strictly only allowing
allocations of 3 bytes or less in the first segment, though, then we can&#x27;t
service that &lt;code&gt;malloc(6)&lt;&#x2F;code&gt;. The trade-off here is that reserving a segment of
memory for smaller allocations gives you less memory to work with for bigger
ones.&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;haskie&quot;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;haskie-triumphant-200px.png&quot; &#x2F;&gt;
&lt;p&gt;
  Hey, &lt;a simulation=&quot;segmented-1&quot; position=4&gt;the first allocation in the dark
  grey free list&lt;&#x2F;a&gt; is 3 bytes! You said this was for allocations 4 bytes and
  up. What gives?
&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Got me again. This implementation I&#x27;ve written will put small allocations in the
dark grey space when the light grey space is full. It will overallocate when it
does this, otherwise we&#x27;d end up with avoidable fragmentation in the dark grey
space thanks to small allocations.&lt;&#x2F;p&gt;
&lt;p&gt;Allocators that split memory up based on the size of allocation are called
&quot;slab allocators.&quot; In practice they have many more size classes than the 2 in
our example.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-quick-malloc-puzzle&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#a-quick-malloc-puzzle&quot;&gt;#&lt;&#x2F;a&gt;
A quick &lt;code&gt;malloc&lt;&#x2F;code&gt; puzzle&lt;&#x2F;h2&gt;
&lt;p&gt;What happens if you &lt;code&gt;malloc(0)&lt;&#x2F;code&gt;? Have a think about this before playing with
the slider below.&lt;&#x2F;p&gt;
&lt;div class=&quot;memory&quot; bytes=32&gt;
  &lt;allocator path=&quot;&#x2F;js&#x2F;allocators&#x2F;freelist.js&quot;&gt;
    &lt;options coalesce=true minsize=4&gt;&lt;&#x2F;options&gt;
  &lt;&#x2F;allocator&gt;
  &lt;malloc id=1 size=0&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=2 size=0&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=3 size=0&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=4 size=0&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=5 size=0&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=6 size=0&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=7 size=0&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=8 size=0&gt;&lt;&#x2F;malloc&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;This is using our free list implementation that mandates a minimum size of 4
bytes for allocations. All memory gets allocated, but none is actually used.
Do you think this is correct behaviour?&lt;&#x2F;p&gt;
&lt;p&gt;It turns out that what happens when you &lt;code&gt;malloc(0)&lt;&#x2F;code&gt; differs between
implementations. Some of them behave as above, allocating space they probably
didn&#x27;t have to. Others will return what&#x27;s called a &quot;null pointer&quot;, a special
pointer that will crash your program if you try to read or write the memory it
points to.  Others pick one specific location in memory and return that same
location for all calls to &lt;code&gt;malloc(0)&lt;&#x2F;code&gt;, regardless how many times it is called.&lt;&#x2F;p&gt;
&lt;p&gt;Moral of the story? Don&#x27;t &lt;code&gt;malloc(0)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;inline-bookkeeping&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#inline-bookkeeping&quot;&gt;#&lt;&#x2F;a&gt;
Inline bookkeeping&lt;&#x2F;h2&gt;
&lt;p&gt;Remember earlier on when you asked about where allocation list and free list
information gets stored, and I gave an unsatisfying answer about how it&#x27;s
stored in some other area of memory we&#x27;ve reserved for ourselves?&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;haskie&quot;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;haskie-concerned-200px.png&quot; &#x2F;&gt;
&lt;p&gt;
  Yes...
&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;This isn&#x27;t the only way to do it. Lots of allocators store information right
next to the blocks of memory they relate to. Have a look at this.&lt;&#x2F;p&gt;
&lt;div class=&quot;memory&quot; bytes=32 slider=false&gt;
  &lt;allocator path=&quot;&#x2F;js&#x2F;allocators&#x2F;inline.js&quot;&gt;
  &lt;&#x2F;allocator&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;What we have here is memory with no allocations, but free list information
stored inline in that memory. Each block of memory, free or used, gets 3
additional bytes of bookkeeping information. If &lt;code&gt;address&lt;&#x2F;code&gt; is the address of the
first byte of the allocation, here&#x27;s the layout of a block:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;address + 0&lt;&#x2F;code&gt; is the &lt;span class=&quot;size&quot;&gt;size&lt;&#x2F;span&gt; of the block&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;address + 1&lt;&#x2F;code&gt; is whether the block is &lt;span class=&quot;free&quot;&gt;free (1)&lt;&#x2F;span&gt; or &lt;span class=&quot;allocated&quot;&gt;used (2)&lt;&#x2F;span&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;address + 2&lt;&#x2F;code&gt; is where the &lt;span class=&quot;usable-memory&quot;&gt;usable memory&lt;&#x2F;span&gt; starts&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;address + 2 + size&lt;&#x2F;code&gt; -- the &lt;span class=&quot;size&quot;&gt;size&lt;&#x2F;span&gt; of the block again&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;So in this above example, the byte at &lt;code&gt;0x0&lt;&#x2F;code&gt; is storing the value 29. This means
it&#x27;s a block containing 29 bytes of memory. The value 1 at &lt;code&gt;0x1&lt;&#x2F;code&gt; indicates that
the block is free memory.&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;haskie&quot;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;haskie-concerned-200px.png&quot; &#x2F;&gt;
&lt;p&gt;
  We store the &lt;span class=&quot;size&quot;&gt;size&lt;&#x2F;span&gt; twice? Isn&#x27;t that wasteful?
&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;It seems wasteful at first, but it is necessary if we want to do any form of
coalescing. Let&#x27;s take a look at an example.&lt;&#x2F;p&gt;
&lt;div class=&quot;memory&quot; bytes=32 slider=false&gt;
  &lt;allocator path=&quot;&#x2F;js&#x2F;allocators&#x2F;inline.js&quot;&gt;
  &lt;&#x2F;allocator&gt;
  &lt;malloc id=1 size=4&gt;&lt;&#x2F;malloc&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Here we&#x27;ve allocated 4 bytes of memory. To do this, our &lt;code&gt;malloc&lt;&#x2F;code&gt; implementation
starts at the beginning of memory and checks to see if the block there is used.
It knows that at &lt;code&gt;address + 1&lt;&#x2F;code&gt; it will find either a 1 or a 2. If it finds a
1, it can check the value at &lt;code&gt;address&lt;&#x2F;code&gt; for how big the block is. If it is big
enough, it can allocate into it. If it&#x27;s not big enough, it knows it can add
the value it finds in &lt;code&gt;address&lt;&#x2F;code&gt; to &lt;code&gt;address&lt;&#x2F;code&gt; to get to the start of the next
block of memory.&lt;&#x2F;p&gt;
&lt;p&gt;This has resulted in the creation of a used block (notice the 2 stored in the
2nd byte), and it has pushed start of the free block forward by 7 bytes. Let&#x27;s
do the same again and allocate another 4 bytes.&lt;&#x2F;p&gt;
&lt;div class=&quot;memory&quot; bytes=32 slider=false&gt;
  &lt;allocator path=&quot;&#x2F;js&#x2F;allocators&#x2F;inline.js&quot;&gt;
  &lt;&#x2F;allocator&gt;
  &lt;malloc id=1 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=2 size=4&gt;&lt;&#x2F;malloc&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Next, let&#x27;s &lt;code&gt;free&lt;&#x2F;code&gt; our first &lt;code&gt;malloc(4)&lt;&#x2F;code&gt;. The implementation of &lt;code&gt;free&lt;&#x2F;code&gt; is where
storing information inline starts to shine. In our previous allocators, we had
to search the allocation list to know the size of the block being &lt;code&gt;free&lt;&#x2F;code&gt;d.  Now
we know we&#x27;ll find it at &lt;code&gt;address&lt;&#x2F;code&gt;. What&#x27;s better than that is that for this
&lt;code&gt;free&lt;&#x2F;code&gt;, we don&#x27;t even need to know how big the allocation is. We can just set
&lt;code&gt;address + 1&lt;&#x2F;code&gt; to 1!&lt;&#x2F;p&gt;
&lt;div class=&quot;memory&quot; bytes=32 slider=false&gt;
  &lt;allocator path=&quot;&#x2F;js&#x2F;allocators&#x2F;inline.js&quot;&gt;
  &lt;&#x2F;allocator&gt;
  &lt;malloc id=1 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=2 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;free id=1&gt;&lt;&#x2F;free&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;How great is that? Simple, fast.&lt;&#x2F;p&gt;
&lt;p&gt;What if we wanted to free the 2nd block of used memory? We know that we want to
coalesce to avoid fragmentation, but how do we do that? This is where the
seemingly wasteful bookkeeping comes into play.&lt;&#x2F;p&gt;
&lt;p&gt;When we coalesce, we check to see the state of the blocks immediately before and
immediately after the block we&#x27;re &lt;code&gt;free&lt;&#x2F;code&gt;ing. We know that we can get to the next
block by adding the value at &lt;code&gt;address&lt;&#x2F;code&gt; to &lt;code&gt;address&lt;&#x2F;code&gt;, but how do we get to the
previous block? We take the value at &lt;code&gt;address - 1&lt;&#x2F;code&gt; and &lt;em&gt;subtract&lt;&#x2F;em&gt; that from
&lt;code&gt;address&lt;&#x2F;code&gt;. Without this duplicated size information at the end of the block, it
would be impossible to find the previous block and impossible to coalesce
properly.&lt;&#x2F;p&gt;
&lt;div class=&quot;memory&quot; bytes=32&gt;
  &lt;allocator path=&quot;&#x2F;js&#x2F;allocators&#x2F;inline.js&quot;&gt;
  &lt;&#x2F;allocator&gt;
  &lt;malloc id=1 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;malloc id=2 size=4&gt;&lt;&#x2F;malloc&gt;
  &lt;free id=1&gt;&lt;&#x2F;free&gt;
  &lt;free id=2&gt;&lt;&#x2F;free&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Allocators that store bookkeeping information like this alongside allocations
are called &quot;boundary tag allocators.&quot;&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;haskie&quot;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;haskie-concerned-200px.png&quot; &#x2F;&gt;
&lt;p&gt;
  What&#x27;s stopping a program from modifying the bookkeeping information? Wouldn&#x27;t
  that completely break memory?
&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Surprisingly, nothing truly prevents this. We rely heavily, as an industry, on
the correctness of code. You might have heard of &quot;buffer overrun&quot; or &quot;use after
free&quot; bugs before. These are when a program modifies memory past the end of an
allocated block, or accidentally uses a block of memory after &lt;code&gt;free&lt;&#x2F;code&gt;ing it.
These are indeed catastrophic. They can result in your program immediately
crashing, they can result in your program crashing in several minutes, hours, or
days time. They can even result in hackers using the bug to gain access to
systems they shouldn&#x27;t have access to.&lt;&#x2F;p&gt;
&lt;p&gt;We&#x27;re seeing a rise in popularity of &quot;memory safe&quot; languages, for example Rust.
These languages invest a lot in making sure it&#x27;s not possible to make these
types of mistake in the first place. Exactly how they do that is outside of
the scope of this article, but if this interests you I highly recommend giving
Rust a try.&lt;&#x2F;p&gt;
&lt;p&gt;You might have also realised that calling &lt;code&gt;free&lt;&#x2F;code&gt; on a pointer that&#x27;s in the
middle of a block of memory could also have disastrous consequences. Depending
on what values are in memory, the allocator could be tricked into thinking it&#x27;s
&lt;code&gt;free&lt;&#x2F;code&gt;ing something but what it&#x27;s really doing is modifying memory it shouldn&#x27;t
be.&lt;&#x2F;p&gt;
&lt;p&gt;To get around this, some allocators inject &quot;magic&quot; values as part of the
bookkeeping information. They store, say, &lt;code&gt;0x55&lt;&#x2F;code&gt; at &lt;code&gt;address + 2&lt;&#x2F;code&gt;.  This would
waste an extra byte of memory per allocation, but would allow them to know when
a mistake has been made. To reduce the impact of this, allocators often disable
this behaviour by default and allow you to enable it only when you&#x27;re debugging.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;playground&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#playground&quot;&gt;#&lt;&#x2F;a&gt;
Playground&lt;&#x2F;h2&gt;
&lt;p&gt;If you&#x27;re keen to take your new found knowledge and try your hand at writing
your own allocators, you can click &lt;a href=&quot;&#x2F;allocator-playground&quot;&gt;here&lt;&#x2F;a&gt; to go to my
allocator playground. You&#x27;ll be able to write JavaScript code that implements
the &lt;code&gt;malloc&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;free&lt;&#x2F;code&gt; API and visualise how it works!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#conclusion&quot;&gt;#&lt;&#x2F;a&gt;
Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;We&#x27;ve covered a lot in this post, and if it has left you yearning for more you
won&#x27;t be disappointed. I&#x27;ve specifically avoided the topics of virtual memory,
&lt;code&gt;brk&lt;&#x2F;code&gt; vs &lt;code&gt;mmap&lt;&#x2F;code&gt;, the role of CPU caches, and the endless tricks real &lt;code&gt;malloc&lt;&#x2F;code&gt;
implementations pull out of their sleeves. There&#x27;s no shortage of information
about memory allocators on the Internet, and if you&#x27;ve read this far you should
be well-placed to dive in to it.&lt;&#x2F;p&gt;
&lt;p&gt;Join the discussion on &lt;a href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=36029087&quot;&gt;Hacker News&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;acknowledgments&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#acknowledgments&quot;&gt;#&lt;&#x2F;a&gt;
Acknowledgments&lt;&#x2F;h3&gt;
&lt;p&gt;Special thanks to the following people:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;chrisdown.name&quot;&gt;Chris Down&lt;&#x2F;a&gt; for lending me his extensive knowledge of real-world
memory allocators.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;zemlan.in&#x2F;&quot;&gt;Anton Verinov&lt;&#x2F;a&gt; for lending me his extensive knowledge of the web,
browser developer tools, and user experience.&lt;&#x2F;li&gt;
&lt;li&gt;Blake Becker, Matt Kaspar, Krista Horn, Jason Peddle, and
&lt;a href=&quot;https:&#x2F;&#x2F;joshwcomeau.com&quot;&gt;Josh W. Comeau&lt;&#x2F;a&gt; for their insight and constructive
reviews.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;!--
## Real-world performance

By making use of boundary tags, we saw that `free` can be made really fast.
No list traversals required, just inspection and manipulation of a few bytes
of bookkeeping information. But `malloc` still has to traverse the list of
all blocks, free or used, to find one that can fit the current request.

How do we make `malloc` fast?

What we&#x27;re asking here isn&#x27;t for the fastest possible `malloc` implementation.
We&#x27;ve already seen that, at the very start of the article. The `malloc` that
can&#x27;t `free`. That&#x27;s not what we want. We want a `malloc` that gets close to
that speed, without creating a fragmented heap. We want high throughput, low
fragmentation.

There&#x27;s no one-size-fits-all solution here, so I will list a few ways real-world
allocators try to achieve this.

### Segmenting&#x2F;binning memory

We touched on this earlier, but a common approach to balancing throughput and
fragmentation is by splitting memory up in to segments reserved for allocations
of a specific size. In our example we had 2 segments: 1 for small allocations
and 1 for big allocations.

A `malloc` implementation called `dlmalloc` (&quot;Doug Lea&#x27;s `malloc`&quot;) splits
memory up in to 64(!) different size classes that it calls &quot;bins.&quot; Each size
class has a linked list of free blocks of memory associated with it. These lists
begin empty, and as memory is `free`d it gets added to the appropriate list.

When there are no readily available free blocks in these bins, memory is
allocated from what `dlmalloc` refers to as &quot;the wilderness.&quot; This is just the
free memory available to the program at the very beginning. `dlmalloc` takes
from here when it needs to, but prefers to look in the size class bins first. It
only takes from the wilderness when it can&#x27;t take from anywhere else.

If memory isn&#x27;t available in the appropriate bin, but is available in the next
bin up, `dlmalloc` will take a larger block, split it in 2, allocate one, and
put the other in the appropriate bin for later use. Likewise, when `free`ing,
`dlmalloc` will coalesce blocks with their neighbours and return the resulting
block to the largest bin it can. These techniques help reduce fragmentation.

### Caching

Another cool trick `dlmalloc` uses is called the &quot;designated victim.&quot; When
`dlmalloc` takes a block from a bin larger than the current allocation, it
caches the remainder block to be used as the preferred location for the next
allocation that does not perfectly match to a bin size.

`dlmalloc` also caches whether or not bins have blocks in them using a bitmap it
calls the &quot;binmap.&quot; This is a 32 bit value where each bit represents the state
of a given bin. If it&#x27;s a 1, the bin has blocks ready to use in it. If it&#x27;s 0,
it doesn&#x27;t. This makes finding an appropriate bin really, really fast.

`phkmalloc`, the spiritual predecessor to `dlmalloc`, maintains a counter of how
many blocks are free in a given &quot;arena&quot; or memory. `phkmalloc` works on a tiered
system, putting smaller blocks inside of larger blocks, in order to be able to
return the larger blocks back to the operating system when they have been
completely freed. It calls these larger blocks &quot;arenas.&quot;

### Locality

I&#x27;ve not touched on this topic at all, but it is very important especially in
more modern `malloc` implementations. Without going in to too much detail,
memory access involves a hierarchy of caches. Retrieving a value from memory is
slow, so between your CPU and your memory sit layers of caches.  Each layer
closer to the CPU is faster but smaller. These caches can range in size from
100MB at the largest layer to a few dozen kilobytes at the smallest. It&#x27;s common
for CPUs to have 3 layers.

When you fetch a value from memory, your CPU will actually fetch more than
needed. It does this because it is likely that memory close together is needed
at the same time. This is called &quot;spatial locality.&quot; Hard drives do the same
thing.

`malloc` is uniquely positioned to take advantage of this fact. If your `malloc`
implementation intentionally places blocks close to blocks that were `malloc`ed
around the same time, it will increase the chance that a single fetch from
memory will hit multiple blocks of soon-needed memory.

Locality is also an argument in favour of storing your bookkeeping information
separate to allocated memory. The more tightly packed a program&#x27;s in-use memory
is, the more likely it is to get cached together. Also, if you need to traverse
lists to find free blocks, and your list traversal works using boundary tags,
you will be accessing memory that is unlikely to be used.  These accesses get
cached, evicting potentially useful memory in the process.

This is why `dlmalloc` maintains its &quot;binmap&quot; separate from the bins themselves.
You can check the status of all bins with minimal cache disturbance.

### Multithreading

The last topic we&#x27;re going to talk about is multithreading. It&#x27;s very common for
computers in 2023 to have many CPU cores, but this wasn&#x27;t always the case. For
example, when `phkmalloc` was written there was no consideration for
multithreading in the implementation. `dlmalloc` is not thread-safe by default,
but comes with an option to make it thread-safe at a huge performance cost.

One of the first `malloc` implementations to optimise for multithreaded
use-cases was `jemalloc` (&quot;Jason Evans `malloc`&quot;). Written around 2006,
`jemalloc` makes the observation that is 2 CPU cores try to access the same
area of the CPU cache, they will &quot;fight&quot; over the &quot;ownership&quot; of that area of
the cache.

What does this mean?

CPU cache is split in to &quot;lines.&quot; These lines are typically 64 bytes in size,
and represent a 64 byte chunk of memory. Each CPU core has its own dedicated set
of caches, so the same 64 byte chunk of memory could potentially be cached on
multiple cores.

When 2 threads running on 2 different cores try to access the same line of
cache, by trying to access the same area of memory and finding it already
cached, it can become a problem. If they both write to it, that will trigger the
cache to be synchronised across CPU cores, and this can be really slow. Without
this synchronisation, the same 64 byte region of memory could appear to hold
different values depending on what core you see it from.

To avoid this, `jemalloc` splits memory up in to 2MB chunks, and each chunk can
only be accessed by 1 thread. Giving threads unique ownership of parts of memory
guarantees that you will avoid this slow cache synchronisation. It also gives
your `malloc` implementation thread-safety, because you know that all threads
will be operating on memory they have sole ownership of.
--&gt;
</content>
            
        </entry>
    
    
        <entry xml:lang="en">
            <title>Load Balancing</title>
            <published>2023-04-10T00:00:00+00:00</published>
            <updated>2023-04-10T00:00:00+00:00</updated>
            <author>
            <name>Unknown</name>
            </author>
            <link rel="alternate" href="https://old.samwho.dev/load-balancing/" type="text/html"/>
            <id>https://old.samwho.dev/load-balancing/</id>
            
            <content type="html">&lt;script type=&quot;module&quot; src=&quot;&#x2F;js&#x2F;load-balancers.js&quot;&gt;&lt;&#x2F;script&gt;
&lt;style&gt;
.simulation {
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    margin-bottom: 2.5em;
}

.load-balancer {
    color: black;
    font-weight: bold;
}

.request {
    color: #04BF8A;
    font-weight: bold;
}

.server {
    color: #999999;
    font-weight: bold;
}

.dropped {
    color: red;
    font-weight: bold;
}

.lds-dual-ring {
  display: inline-block;
  width: 80px;
  height: 80px;
}
.lds-dual-ring:after {
  content: &quot; &quot;;
  display: block;
  width: 64px;
  height: 64px;
  margin: 8px;
  border-radius: 50%;
  border: 6px solid #000;
  border-color: #000 transparent #000 transparent;
  animation: lds-dual-ring 1.2s linear infinite;
}
@keyframes lds-dual-ring {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}
&lt;&#x2F;style&gt;
&lt;p&gt;Past a certain point, web applications outgrow a single server deployment.
Companies either want to increase their availability, scalability, or both! To
do this, they deploy their application across multiple servers with a load
balancer in front to distribute incoming requests. Big companies may need
thousands of servers running their web application to handle the load.&lt;&#x2F;p&gt;
&lt;p&gt;In this post we&#x27;re going to focus on the ways that a single load balancer might
distribute HTTP requests to a set of servers. We&#x27;ll start from the bottom and
work our way up to modern load balancing algorithms.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;visualising-the-problem&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#visualising-the-problem&quot;&gt;#&lt;&#x2F;a&gt;
Visualising the problem&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s start at the beginning: a single &lt;span class=&quot;load-balancer&quot;&gt;load
balancer&lt;&#x2F;span&gt; sending &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; to a single &lt;span
class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt;. &lt;span class=&quot;request&quot;&gt;Requests&lt;&#x2F;span&gt; are being
sent at a rate of 1 request per second (RPS), and each &lt;span
class=&quot;request&quot;&gt;request&lt;&#x2F;span&gt; reduces in size as the &lt;span
class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; processes it.&lt;&#x2F;p&gt;
&lt;div id=&quot;1&quot; class=&quot;simulation&quot; style=&quot;height: 200px&quot;&gt;
    &lt;div class=&quot;lds-dual-ring&quot;&gt;&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;For a lot of websites, this setup works just fine. Modern &lt;span
class=&quot;server&quot;&gt;servers&lt;&#x2F;span&gt; are powerful and can handle a lot of &lt;span
class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt;. But what happens when they can&#x27;t keep up?&lt;&#x2F;p&gt;
&lt;div id=&quot;2&quot; class=&quot;simulation&quot; style=&quot;height: 200px&quot;&gt;
    &lt;div class=&quot;lds-dual-ring&quot;&gt;&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Here we see that a rate of 3 RPS causes some &lt;span
class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; to get &lt;span class=&quot;dropped&quot;&gt;dropped&lt;&#x2F;span&gt;. If
a &lt;span class=&quot;request&quot;&gt;request&lt;&#x2F;span&gt; arrives at the &lt;span
class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; while another &lt;span class=&quot;request&quot;&gt;request&lt;&#x2F;span&gt;
is being processed, the &lt;span class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; will &lt;span
class=&quot;dropped&quot;&gt;drop&lt;&#x2F;span&gt; it.  This will result in an error being shown to the
user and is something we want to avoid. We can add another &lt;span
class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; to our &lt;span class=&quot;load-balancer&quot;&gt;load
balancer&lt;&#x2F;span&gt; to fix this.&lt;&#x2F;p&gt;
&lt;div id=&quot;3&quot; class=&quot;simulation&quot; style=&quot;height: 200px&quot;&gt;
    &lt;div class=&quot;lds-dual-ring&quot;&gt;&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;No more &lt;span class=&quot;dropped&quot;&gt;dropped&lt;&#x2F;span&gt; &lt;span
class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt;! The way our &lt;span class=&quot;load-balancer&quot;&gt;load
balancer&lt;&#x2F;span&gt; is behaving here, sending a request to each &lt;span
class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; in turn, is called &quot;round robin&quot; load balancing.
It&#x27;s one of the simplest forms of load balancing, and works well when your &lt;span
class=&quot;server&quot;&gt;servers&lt;&#x2F;span&gt; are all equally powerful and your &lt;span
class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; are all equally expensive.&lt;&#x2F;p&gt;
&lt;div id=&quot;4&quot; class=&quot;simulation&quot; style=&quot;height: 200px&quot;&gt;
    &lt;div class=&quot;lds-dual-ring&quot;&gt;&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;when-round-robin-doesn-t-cut-it&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#when-round-robin-doesn-t-cut-it&quot;&gt;#&lt;&#x2F;a&gt;
When round robin doesn&#x27;t cut it&lt;&#x2F;h2&gt;
&lt;p&gt;In the real world, it&#x27;s rare for &lt;span class=&quot;server&quot;&gt;servers&lt;&#x2F;span&gt; to be
equally powerful and &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; to be equally
expensive. Even if you use the exact same &lt;span class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt;
hardware, performance may differ. Applications may have to service many
different types of &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt;, and these will likely
have different performance characteristics.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s see what happens when we vary &lt;span class=&quot;request&quot;&gt;request&lt;&#x2F;span&gt; cost.
In the following simulation, &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; aren&#x27;t
equally expensive. You&#x27;ll be able to see this by some &lt;span
class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; taking longer to shrink than others.&lt;&#x2F;p&gt;
&lt;div id=&quot;5&quot; class=&quot;simulation&quot; style=&quot;height: 200px&quot;&gt;
    &lt;div class=&quot;lds-dual-ring&quot;&gt;&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;While most &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; get served successfully, we do
&lt;span class=&quot;dropped&quot;&gt;drop&lt;&#x2F;span&gt; some. One of the ways we can mitigate this is
to have a &quot;request queue.&quot;&lt;&#x2F;p&gt;
&lt;div id=&quot;6&quot; class=&quot;simulation&quot; style=&quot;height: 250px&quot;&gt;
    &lt;div class=&quot;lds-dual-ring&quot;&gt;&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Request queues help us deal with uncertainty, but it&#x27;s a trade-off. We will
&lt;span class=&quot;dropped&quot;&gt;drop&lt;&#x2F;span&gt; fewer &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt;,
but at the cost of some &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; having a higher
latency. If you watch the above simulation long enough, you might notice the
&lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; subtly changing colour. The longer they go
without being served, the more their colour will change. You&#x27;ll also notice that
thanks to the &lt;span class=&quot;request&quot;&gt;request&lt;&#x2F;span&gt; cost variance, &lt;span
class=&quot;server&quot;&gt;servers&lt;&#x2F;span&gt; start to exhibit an imbalance. Queues will get
backed up on &lt;span class=&quot;server&quot;&gt;servers&lt;&#x2F;span&gt; that get unlucky and have to
serve multiple expensive &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; in a row. If
a queue is full, we will &lt;span class=&quot;dropped&quot;&gt;drop&lt;&#x2F;span&gt; the &lt;span
class=&quot;request&quot;&gt;request&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Everything said above applies equally to &lt;span class=&quot;server&quot;&gt;servers&lt;&#x2F;span&gt;
that vary in power. In the next simulation we also vary the power of each
&lt;span class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt;, which is represented visually with a darker
shade of grey.&lt;&#x2F;p&gt;
&lt;div id=&quot;7&quot; class=&quot;simulation&quot; style=&quot;height: 250px&quot;&gt;
    &lt;div class=&quot;lds-dual-ring&quot;&gt;&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;The &lt;span class=&quot;server&quot;&gt;servers&lt;&#x2F;span&gt; are given a random power value, but odds
are some are less powerful than others and quickly start to &lt;span
class=&quot;dropped&quot;&gt;drop&lt;&#x2F;span&gt; &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt;. At the same
time, the more powerful &lt;span class=&quot;server&quot;&gt;servers&lt;&#x2F;span&gt; sit idle most of the
time. This scenario shows the key weakness of round robin: variance.&lt;&#x2F;p&gt;
&lt;p&gt;Despite its flaws, however, round robin is still the default HTTP load balancing
method for &lt;a href=&quot;https:&#x2F;&#x2F;nginx.org&#x2F;en&#x2F;docs&#x2F;http&#x2F;load_balancing.html&quot;&gt;nginx&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;improving-on-round-robin&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#improving-on-round-robin&quot;&gt;#&lt;&#x2F;a&gt;
Improving on round robin&lt;&#x2F;h2&gt;
&lt;p&gt;It&#x27;s possible to tweak round robin to perform better with variance. There&#x27;s an
algorithm called &quot;weighted round robin&quot; which involves getting humans
to tag each &lt;span class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; with a weight that dictates how
many &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; to send to it.&lt;&#x2F;p&gt;
&lt;p&gt;In this simulation, we use each &lt;span class=&quot;server&quot;&gt;server&#x27;s&lt;&#x2F;span&gt; known power
value as its weight, and we give more powerful &lt;span
class=&quot;server&quot;&gt;servers&lt;&#x2F;span&gt; more &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; as we
loop through them.&lt;&#x2F;p&gt;
&lt;div id=&quot;8&quot; class=&quot;simulation&quot; style=&quot;height: 250px&quot;&gt;
    &lt;div class=&quot;lds-dual-ring&quot;&gt;&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;While this handles the variance of &lt;span class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; power
better than vanilla round robin, we still have &lt;span
class=&quot;request&quot;&gt;request&lt;&#x2F;span&gt; variance to contend with. In practice, getting
humans to set the weight by hand falls apart quickly. Boiling &lt;span
class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; performance down to a single number is hard, and
would require careful load testing with real workloads. This is rarely done, so
another variant of weighted round robin calculates weights dynamically by using
a proxy metric: latency.&lt;&#x2F;p&gt;
&lt;p&gt;It stands to reason that if one &lt;span class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; serves
&lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; 3 times faster than another &lt;span class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt;, it&#x27;s probably 3 times faster and should receive
3 times more &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; than the other &lt;span class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;div id=&quot;9&quot; class=&quot;simulation&quot; style=&quot;height: 250px&quot;&gt;
    &lt;div class=&quot;lds-dual-ring&quot;&gt;&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;I&#x27;ve added text to each &lt;span class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; this time that shows
the average latency of the last 3 &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; served.
We then decide whether to send 1, 2, or 3 &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt;
to each &lt;span class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; based on the relative differences in
the latencies. The result is very similar to the initial weighted round robin
simulation, but there&#x27;s no need to specify the weight of each &lt;span
class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; up front. This algorithm will also be able to adapt
to changes in &lt;span class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; performance over time. This is
called &quot;dynamic weighted round robin.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s see how it handles a complex situation, with high variance in both &lt;span
class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; power and &lt;span class=&quot;request&quot;&gt;request&lt;&#x2F;span&gt;
cost. The following simulation uses randomised values, so feel free to refresh
the page a few times to see it adapt to new variants.&lt;&#x2F;p&gt;
&lt;div id=&quot;10&quot; class=&quot;simulation&quot; style=&quot;height: 250px&quot;&gt;
    &lt;div class=&quot;lds-dual-ring&quot;&gt;&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;moving-away-from-round-robin&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#moving-away-from-round-robin&quot;&gt;#&lt;&#x2F;a&gt;
Moving away from round robin&lt;&#x2F;h2&gt;
&lt;p&gt;Dynamic weighted round robin seems to account well for variance in both &lt;span
class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; power and &lt;span class=&quot;request&quot;&gt;request
&lt;&#x2F;span&gt; cost. But what if I told you we could do even better, and with a simpler
algorithm?&lt;&#x2F;p&gt;
&lt;div id=&quot;11&quot; class=&quot;simulation&quot; style=&quot;height: 250px&quot;&gt;
    &lt;div class=&quot;lds-dual-ring&quot;&gt;&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;This is called &quot;least connections&quot; load balancing.&lt;&#x2F;p&gt;
&lt;p&gt;Because the &lt;span class=&quot;load-balancer&quot;&gt;load balancer&lt;&#x2F;span&gt; sits between the
&lt;span class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; and the user, it can accurately keep track
of how many outstanding &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; each &lt;span
class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; has. Then when a new &lt;span class=&quot;request&quot;&gt;
request&lt;&#x2F;span&gt; comes in and it&#x27;s time to determine where to send it, it knows
which &lt;span class=&quot;server&quot;&gt;servers&lt;&#x2F;span&gt; have the least work to do and
prioritises those.&lt;&#x2F;p&gt;
&lt;p&gt;This algorithm performs extremely well regardless how much variance exists.
It cuts through uncertainty by maintaining an accurate understanding of what
each &lt;span class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; is doing. It also has the benefit of
being very simple to implement.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s see this in action in a similarly complex simulation, the same parameters
we gave the dynamic weighted round robin algorithm above. Again, these
parameters are randomised within given ranges, so refresh the page to see new
variants.&lt;&#x2F;p&gt;
&lt;div id=&quot;12&quot; class=&quot;simulation&quot; style=&quot;height: 250px&quot;&gt;
    &lt;div class=&quot;lds-dual-ring&quot;&gt;&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;While this algorithm is a great balance between simplicity and performance, it&#x27;s
not immune to &lt;span class=&quot;dropped&quot;&gt;dropping&lt;&#x2F;span&gt; &lt;span
class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt;. However, what you&#x27;ll notice is that the only
time this algorithm &lt;span class=&quot;dropped&quot;&gt;drops&lt;&#x2F;span&gt; &lt;span
class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; is when there is literally no more queue space
available. It will make sure all available resources are in use, and that makes
it a great default choice for most workloads.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;optimizing-for-latency&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#optimizing-for-latency&quot;&gt;#&lt;&#x2F;a&gt;
Optimizing for latency&lt;&#x2F;h2&gt;
&lt;p&gt;Up until now I&#x27;ve been avoiding a crucial part of the discussion: what we&#x27;re
optimising for. Implicitly, I&#x27;ve been considering &lt;span
class=&quot;dropped&quot;&gt;dropped&lt;&#x2F;span&gt; &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; to be
really bad and seeking to avoid them. This is a nice goal, but it&#x27;s not the
metric we most want to optimise for in an HTTP &lt;span class=&quot;load-balancer&quot;&gt;load
balancer&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;What we&#x27;re often more concerned about is latency. This is measured in
milliseconds from the moment a &lt;span class=&quot;request&quot;&gt;request&lt;&#x2F;span&gt; is created
to the moment it has been served. When we&#x27;re discussing latency in this context,
it is common to talk about different &quot;percentiles.&quot; For example, the 50th
percentile (also called the &quot;median&quot;) is defined as the millisecond value for
which 50% of requests are below, and 50% are above.&lt;&#x2F;p&gt;
&lt;p&gt;I ran 3 simulations with identical parameters for 60 seconds and took a variety
of measurements every second. Each simulation varied only by the load balancing
algorithm used. Let&#x27;s compare the medians for each of the 3 simulations:&lt;&#x2F;p&gt;
&lt;div id=&quot;graph-medians&quot;&gt;&lt;&#x2F;div&gt;
&lt;p&gt;You might not have expected it, but round robin has the best median latency. If
we weren&#x27;t looking at any other data points, we&#x27;d miss the full story.  Let&#x27;s
take a look at the 95th and 99th percentiles.&lt;&#x2F;p&gt;
&lt;div id=&quot;graph-higher&quot;&gt;&lt;&#x2F;div&gt;
&lt;p&gt;Note: there&#x27;s no colour difference between the different percentiles for each
load balancing algorithm. Higher percentiles will always be higher on the graph.&lt;&#x2F;p&gt;
&lt;p&gt;We see that round robin doesn&#x27;t perform well in the higher percentiles.  How can
it be that round robin has a great median, but bad 95th and 99th percentiles?&lt;&#x2F;p&gt;
&lt;p&gt;In round robin, the state of each &lt;span class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; isn&#x27;t
considered, so you&#x27;ll get quite a lot of &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt;
going to &lt;span class=&quot;server&quot;&gt;servers&lt;&#x2F;span&gt; that are idle. This is how we get
the low 50th percentile. On the flip side, we&#x27;ll also happily send &lt;span
class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; to &lt;span class=&quot;server&quot;&gt;servers&lt;&#x2F;span&gt; that are
overloaded, hence the bad 95th and 99th percentiles.&lt;&#x2F;p&gt;
&lt;p&gt;We can take a look at the full data in histogram form:&lt;&#x2F;p&gt;
&lt;div id=&quot;histogram-1&quot;&gt;&lt;&#x2F;div&gt;
&lt;p&gt;I chose the parameters for these simulations to avoid &lt;span
class=&quot;dropped&quot;&gt;dropping&lt;&#x2F;span&gt; any &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt;. This
guarantees we compare the same number of data points for all 3 algorithms.
Let&#x27;s run the simulations again but with an increased RPS value, designed to
push all of the algorithms past what they can handle.  The following is a graph
of cumulative &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; &lt;span
class=&quot;dropped&quot;&gt;dropped&lt;&#x2F;span&gt; over time.&lt;&#x2F;p&gt;
&lt;div id=&quot;graph-dropped&quot;&gt;&lt;&#x2F;div&gt;
&lt;p&gt;Least connections handles overload much better, but the cost of doing that is
slightly higher 95th and 99th percentile latencies. Depending on your use-case,
this might be a worthwhile trade-off.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;one-last-algorithm&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#one-last-algorithm&quot;&gt;#&lt;&#x2F;a&gt;
One last algorithm&lt;&#x2F;h2&gt;
&lt;p&gt;If we &lt;em&gt;really&lt;&#x2F;em&gt; want to optimise for latency, we need an algorithm that takes
latency into account. Wouldn&#x27;t it be great if we could combine the dynamic
weighted round robin algorithm with the least connections algorithm? The latency
of weighted round robin and the resilience of least connections.&lt;&#x2F;p&gt;
&lt;p&gt;Turns out we&#x27;re not the first people to have this thought. Below is a simulation
using an algorithm called &quot;peak exponentially weighted moving average&quot; (or
PEWMA). It&#x27;s a long and complex name but hang in there, I&#x27;ll break down how it
works in a moment.&lt;&#x2F;p&gt;
&lt;div id=&quot;13&quot; class=&quot;simulation&quot; style=&quot;height: 250px&quot;&gt;
    &lt;div class=&quot;lds-dual-ring&quot;&gt;&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;I&#x27;ve set specific parameters for this simulation that are guaranteed to exhibit
an expected behaviour. If you watch closely, you&#x27;ll notice that the algorithm
just stops sending &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; to the leftmost &lt;span
class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; after a while. It does this because it figures out
that all of the other &lt;span class=&quot;server&quot;&gt;servers&lt;&#x2F;span&gt; are faster, and
there&#x27;s no need to send &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; to the slowest
one. That will just result in &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt; with a
higher latency.&lt;&#x2F;p&gt;
&lt;p&gt;So how does it do this? It combines techniques from dynamic weighted round robin
with techniques from least connections, and sprinkles a little bit of its own
magic on top.&lt;&#x2F;p&gt;
&lt;p&gt;For each &lt;span class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt;, the algorithm keeps track of the
latency from the last N &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt;. Instead of using
this to calculate an average, it sums the values but with an exponentially
decreasing scale factor. This results in a value where the older a latency is,
the less it contributes to the sum. Recent &lt;span class=&quot;request&quot;&gt;requests&lt;&#x2F;span&gt;
influence the calculation more than old ones.&lt;&#x2F;p&gt;
&lt;p&gt;That value is then taken and multiplied by the number of open connections to the
&lt;span class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; and the result is the value we use to choose
which &lt;span class=&quot;server&quot;&gt;server&lt;&#x2F;span&gt; to send the next &lt;span
class=&quot;request&quot;&gt;request&lt;&#x2F;span&gt; to. Lower is better.&lt;&#x2F;p&gt;
&lt;p&gt;So how does it compare? First let&#x27;s take a look at the 50th, 95th, and 99th
percentiles when compared against the least connections data from earlier.&lt;&#x2F;p&gt;
&lt;div id=&quot;pewma-graph&quot;&gt;&lt;&#x2F;div&gt;
&lt;p&gt;We see a marked improvement across the board! It&#x27;s far more pronounced at the
higher percentiles, but consistently present for the median as well. Here we
can see the same data in histogram form.&lt;&#x2F;p&gt;
&lt;div id=&quot;pewma-histogram&quot;&gt;&lt;&#x2F;div&gt;
&lt;p&gt;How about &lt;span class=&quot;dropped&quot;&gt;dropped&lt;&#x2F;span&gt; &lt;span
class=&quot;requests&quot;&gt;requests&lt;&#x2F;span&gt;?&lt;&#x2F;p&gt;
&lt;div id=&quot;pewma-dropped&quot;&gt;&lt;&#x2F;div&gt;
&lt;p&gt;It starts out performing better, but over time performs worse than least
connections. This makes sense. PEWMA is opportunistic in that it tries to get
the best latency, and this means it may sometimes leave a &lt;span class=&quot;server&quot;&gt;
server&lt;&#x2F;span&gt; less than fully loaded.&lt;&#x2F;p&gt;
&lt;p&gt;I want to add here that PEWMA has a lot of parameters that can be tweaked. The
implementation I wrote for this post uses a configuration that seemed to work
well for the situations I tested it in, but further tweaking could get you
better results vs least connections. This is one of the downsides of PEWMA vs
least connections: extra complexity.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#conclusion&quot;&gt;#&lt;&#x2F;a&gt;
Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;I spent a long time on this post. It was difficult to balance realism against
ease of understanding, but I feel good about where I landed. I&#x27;m hopeful that
being able to see how these complex systems behave in practice, in ideal and
less-than-ideal scenarios, helps you grow an intuitive understanding of when
they would best apply to your workloads.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Obligatory disclaimer&lt;&#x2F;strong&gt;: You must always benchmark your own workloads over
taking advice from the Internet as gospel. My simulations here ignore some real
life constraints (server slow start, network latency), and are set up to display
specific properties of each algorithm. They aren&#x27;t realistic benchmarks to be
taken at face value.&lt;&#x2F;p&gt;
&lt;p&gt;To round this out, I leave you with a version of the simulation that lets you
tweak most of the parameters in real time. Have fun!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;EDIT&lt;&#x2F;strong&gt;: &lt;em&gt;Thanks to everyone who participated in the discussions on
&lt;a href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=35588797&quot;&gt;Hacker News&lt;&#x2F;a&gt;,
&lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;samwhoo&#x2F;status&#x2F;1645429789107318789?s=20&quot;&gt;Twitter&lt;&#x2F;a&gt; and
&lt;a href=&quot;https:&#x2F;&#x2F;lobste.rs&#x2F;s&#x2F;kydugs&#x2F;load_balancing&quot;&gt;Lobste.rs&lt;&#x2F;a&gt;!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;You all had a tonne of great questions and I tried to answer all of them.
Some of the common themes were about missing things, either algorithms (like
&quot;power of 2 choices&quot;) or downsides of algorithms covered (like how &quot;least
connections&quot; handles errors from servers).&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;I tried to strike a balance between post length and complexity of the
simulations. I&#x27;m quite happy with where I landed, but like you I also wish I
could have covered more. I&#x27;d love to see people taking inspiration from this
and covering more topics in this space in a visual way. Please ping me if you
do!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;The other common theme was &quot;how did you make this?&quot; I used
&lt;a href=&quot;https:&#x2F;&#x2F;pixijs.com&#x2F;&quot;&gt;PixiJS&lt;&#x2F;a&gt; and I&#x27;m really happy with how it turned out. It&#x27;s
my first time using this library and it was quite easy to get to grips with.
If writing visual explanations like this are something you&#x27;re interested in,
I recommend it!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;playground&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#playground&quot;&gt;#&lt;&#x2F;a&gt;
Playground&lt;&#x2F;h2&gt;
&lt;div id=&quot;fin&quot; class=&quot;simulation&quot; style=&quot;height: 450px; margin-top: 20px&quot;&gt;
    &lt;div class=&quot;lds-dual-ring&quot;&gt;&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
</content>
            
        </entry>
    
    
        <entry xml:lang="en">
            <title>Practical Problems with Auto-Increment</title>
            <published>2023-03-25T00:00:00+00:00</published>
            <updated>2023-03-25T00:00:00+00:00</updated>
            <author>
            <name>Unknown</name>
            </author>
            <link rel="alternate" href="https://old.samwho.dev/blog/practical-problems-with-auto-increment/" type="text/html"/>
            <id>https://old.samwho.dev/blog/practical-problems-with-auto-increment/</id>
            
            <content type="html">&lt;p&gt;In this post I&#x27;m going to demonstrate 2 reasons I will be avoiding
auto-increment fields in Postgres and MySQL in future. I&#x27;m going to prefer using
UUID fields unless I have a &lt;em&gt;very&lt;&#x2F;em&gt; good reason not to.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;mysql-8-0-auto-increment-id-re-use&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#mysql-8-0-auto-increment-id-re-use&quot;&gt;#&lt;&#x2F;a&gt;
MySQL &amp;lt;8.0 auto-increment ID re-use&lt;&#x2F;h2&gt;
&lt;p&gt;If you&#x27;re running an older version of MySQL, it&#x27;s possible for auto-incrementing
IDs to get re-used. Let&#x27;s see this in action.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ docker volume create mysql-data
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ docker run --platform linux&#x2F;amd64 -e MYSQL_ROOT_PASSWORD=my-secret-pw -p 3306:3306 -v mysql-data:&#x2F;var&#x2F;lib&#x2F;mysql mysql:5.7
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This gets us a Docker container of MySQL 5.7 running, attached to a volume that
will persist the data between runs of this container. Next let&#x27;s get a simple
schema we can work with:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ docker run -it --rm --network host --platform linux&#x2F;amd64 mysql:5.7 mysql -h 127.0.0.1 -P 3306 -u root -p
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mysql&amp;gt; CREATE DATABASE my_database;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Query OK, 1 row affected (0.01 sec)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mysql&amp;gt; USE my_database;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Database changed
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mysql&amp;gt; CREATE TABLE my_table (
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    -&amp;gt; ID INT AUTO_INCREMENT PRIMARY KEY
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    -&amp;gt; );
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Query OK, 0 rows affected (0.02 sec)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now let&#x27;s insert a couple of rows.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mysql&amp;gt; INSERT INTO my_table () VALUES ();
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Query OK, 1 row affected (0.03 sec)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mysql&amp;gt; INSERT INTO my_table () VALUES ();
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Query OK, 1 row affected (0.01 sec)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mysql&amp;gt; INSERT INTO my_table () VALUES ();
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Query OK, 1 row affected (0.01 sec)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mysql&amp;gt; SELECT * FROM my_table;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;+----+
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;| ID |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;+----+
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|  1 |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|  2 |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|  3 |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;+----+
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;3 rows in set (0.01 sec)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So far so good. We can restart the MySQL server and run the same SELECT
statement again and get the same result.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s delete a row.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mysql&amp;gt; DELETE FROM my_table WHERE ID=3;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Query OK, 1 row affected (0.03 sec)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mysql&amp;gt; SELECT * FROM my_table;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;+----+
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;| ID |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;+----+
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|  1 |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|  2 |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;+----+
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;2 rows in set (0.00 sec)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s insert a new row to make sure the ID 3 doesn&#x27;t get reused.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mysql&amp;gt; INSERT INTO my_table () VALUES ();
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Query OK, 1 row affected (0.02 sec)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mysql&amp;gt; SELECT * FROM my_table;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;+----+
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;| ID |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;+----+
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|  1 |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|  2 |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|  4 |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;+----+
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;3 rows in set (0.00 sec)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Perfect. Let&#x27;s delete that latest row, restart the server, and then insert
a new row.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mysql&amp;gt; DELETE FROM my_table WHERE ID=4;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Query OK, 1 row affected (0.01 sec)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mysql&amp;gt; SELECT * FROM my_table;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ERROR 2013 (HY000): Lost connection to MySQL server during query
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ docker run -it --rm --network host --platform linux&#x2F;amd64 mysql:5.7 mysql -h 127.0.0.1 -P 3306 -u root -p
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mysql&amp;gt; USE my_database;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Database changed
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mysql&amp;gt; SELECT * FROM my_table;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;+----+
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;| ID |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;+----+
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|  1 |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|  2 |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;+----+
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;2 rows in set (0.00 sec)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mysql&amp;gt; INSERT INTO my_table () VALUES ();
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Query OK, 1 row affected (0.03 sec)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mysql&amp;gt; SELECT * FROM my_table;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;+----+
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;| ID |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;+----+
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|  1 |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|  2 |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;|  3 |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;+----+
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;3 rows in set (0.00 sec)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Eep. MySQL has re-used the ID 3. This is because the way that auto-increment
works in InnoDB is, on server restart, it will figure out what the next
ID to use is by effectively running this query:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;SQL&quot; class=&quot;language-SQL z-code&quot;&gt;&lt;code class=&quot;language-SQL&quot; data-lang=&quot;SQL&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-function z-aggregate z-sql&quot;&gt;MAX&lt;&#x2F;span&gt;(ID) &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; my_table;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you had deleted the most recent records from the table just before restart,
IDs that had been used will be re-used when the server comes back up.&lt;&#x2F;p&gt;
&lt;p&gt;In theory, this &lt;em&gt;shouldn&#x27;t&lt;&#x2F;em&gt; cause you trouble. Best practice dictates that
you shouldn&#x27;t be using IDs from database tables outside of that table unless
it&#x27;s some foreign key field, and you certainly wouldn&#x27;t leak that ID out of
your system, right?&lt;&#x2F;p&gt;
&lt;p&gt;In practice, this stuff happens and can cause devastatingly subtle bugs. MySQL
8.0 changed this behaviour by storing the auto-increment value on disk in a way
that persists across restarts.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;postgres-sequence-values-don-t-get-replicated&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#postgres-sequence-values-don-t-get-replicated&quot;&gt;#&lt;&#x2F;a&gt;
Postgres sequence values don&#x27;t get replicated&lt;&#x2F;h2&gt;
&lt;p&gt;Like MySQL 8.0, Postgres stores auto-increment values on disk. It does this in
a schema object called a &quot;sequence.&quot; When you create an auto-incrementing
field in Postgres, behind the scenes a sequence will be created to back that
field and durably keep track of what the next value should be.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s take a look at that in practice.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ docker volume create postgres-14-data
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ docker run --network host -e POSTGRES_PASSWORD=my-secret-pw -v postgres-14-data:&#x2F;var&#x2F;lib&#x2F;postgresql&#x2F;data -p postgres:14
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With Postgres up and running, let&#x27;s go ahead and create our table:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ docker run -it --rm --network host postgres:14 psql -h 127.0.0.1 -U postgres
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;postgres=# CREATE TABLE my_table (id SERIAL PRIMARY KEY);
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;CREATE TABLE
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And insert a few rows:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;postgres=# INSERT INTO my_table DEFAULT VALUES;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;INSERT 0 1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;postgres=# INSERT INTO my_table DEFAULT VALUES;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;INSERT 0 1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;postgres=# INSERT INTO my_table DEFAULT VALUES;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;INSERT 0 1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;postgres=# SELECT * FROM my_table;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; id
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;----
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  2
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  3
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;(3 rows)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So far so good. Let&#x27;s take a look at the table:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;postgres=# \d my_table
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;                            Table &amp;quot;public.my_table&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; Column |  Type   | Collation | Nullable |               Default
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;--------+---------+-----------+----------+--------------------------------------
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; id     | integer |           | not null | nextval(&amp;#39;my_table_id_seq&amp;#39;::regclass)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Indexes:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &amp;quot;my_table_pkey&amp;quot; PRIMARY KEY, btree (id)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This output tells us that the default value for our &lt;code&gt;id&lt;&#x2F;code&gt; field is the &lt;code&gt;nextval&lt;&#x2F;code&gt;
of &lt;code&gt;my_table_id_seq&lt;&#x2F;code&gt;. Let&#x27;s take a look at &lt;code&gt;my_table_id_seq&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;postgres=# \d my_table_id_seq
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;                  Sequence &amp;quot;public.my_table_id_seq&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Type   | Start | Minimum |  Maximum   | Increment | Cycles? | Cache
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;---------+-------+---------+------------+-----------+---------+-------
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; integer |     1 |       1 | 2147483647 |         1 | no      |     1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Owned by: public.my_table.id
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;postgres=# SELECT currval(&amp;#39;my_table_id_seq&amp;#39;);
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; currval
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;---------
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;       3
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;(1 row)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Neat, we have a bonafide object in Postgres that&#x27;s keeping track of the
auto-incrementing ID value. If we were to repeat what we did in MySQL, delete
some rows and restart, we wouldn&#x27;t have the same problem here. &lt;code&gt;my_table_id_seq&lt;&#x2F;code&gt;
is saved to disk and doesn&#x27;t lose its place.&lt;&#x2F;p&gt;
&lt;p&gt;Or does it?&lt;&#x2F;p&gt;
&lt;p&gt;If you want to update Postgres to a new major version, the way you typically
accomplish that is by creating a new Postgres instance on the version you want
to upgrade to, logically replicate from the old instance to the new one, and
then switch your application to talk to the new one.&lt;&#x2F;p&gt;
&lt;p&gt;First we need to restart our Postgres 14 with some new configuration to allow
logical replication:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ docker run --network host -e POSTGRES_PASSWORD=my-secret-pw -v postgres-14-data:&#x2F;var&#x2F;lib&#x2F;postgresql&#x2F;data -p postgres:14 -c wal_level=logical
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now let&#x27;s get Postgres 15 up and running:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ docker volume create postgres-15-data
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ docker run --network host -e POSTGRES_PASSWORD=my-secret-pw -v postgres-15-data:&#x2F;var&#x2F;lib&#x2F;postgresql&#x2F;data postgres:15 postgres:14 -c wal_level=logical -p 5431
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next up, we create a &quot;publication&quot; on our Postgres 14 instance:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;postgres=# CREATE PUBLICATION my_publication FOR ALL TABLES;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;CREATE PUBLICATION
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then we create our &quot;my_table&quot; table and a &quot;subscription&quot; on our Postgres 15
instance:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;postgres=# CREATE TABLE my_table (id SERIAL PRIMARY KEY);
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;CREATE TABLE
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;postgres=# CREATE SUBSCRIPTION my_subscription CONNECTION &amp;#39;host=127.0.0.1 port=5432 dbname=postgres user=postgres password=my-secret-pw&amp;#39; PUBLICATION my_publication;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;NOTICE:  created replication slot &amp;quot;my_subscription&amp;quot; on publisher
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;CREATE SUBSCRIPTION
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After doing this, we should see data syncing between old and new instances:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ docker run -it --rm --network host postgres:15 psql -h 127.0.0.1 -U postgres -p 5432 -c &amp;quot;SELECT * FROM my_table&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; id
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;----
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  2
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  3
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;(3 rows)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ docker run -it --rm --network host postgres:15 psql -h 127.0.0.1 -U postgres -p 5431 -c &amp;quot;SELECT * FROM my_table&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; id
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;----
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  2
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  3
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;(3 rows)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ docker run -it --rm --network host postgres:15 psql -h 127.0.0.1 -U postgres -p 5432 -c &amp;quot;INSERT INTO my_table DEFAULT VALUES&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;INSERT 0 1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ docker run -it --rm --network host postgres:15 psql -h 127.0.0.1 -U postgres -p 5431 -c &amp;quot;SELECT * FROM my_table&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; id
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;----
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  2
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  3
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  4
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;(4 rows)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So what&#x27;s the problem?&lt;&#x2F;p&gt;
&lt;p&gt;Well...&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ docker run -it --rm --network host postgres:15 psql -h 127.0.0.1 -U postgres -p 5432 -c &amp;quot;SELECT nextval(&amp;#39;my_table_id_seq&amp;#39;)&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; nextval
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;---------
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;       5
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;(1 row)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ docker run -it --rm --network host postgres:15 psql -h 127.0.0.1 -U postgres -p 5431 -c &amp;quot;SELECT nextval(&amp;#39;my_table_id_seq&amp;#39;)&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; nextval
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;---------
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;       1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;(1 row)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The sequence value is not replicated. If we tried to insert a row into Postgres
15 we get this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ docker run -it --rm --network host postgres:15 psql -h 127.0.0.1 -U postgres -p 5431 -c &amp;quot;INSERT INTO my_table DEFAULT VALUES&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ERROR:  duplicate key value violates unique constraint &amp;quot;my_table_pkey&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;DETAIL:  Key (id)=(2) already exists.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note: It&#x27;s tried to insert id=2 here because when we called &lt;code&gt;nextval&lt;&#x2F;code&gt; earlier, it
modified the sequence.&lt;&#x2F;p&gt;
&lt;p&gt;This can make major Postgres version updates very tricky if you rely heavily on
auto-incrementing ID fields. You need to modify the sequence values manually to
values you know for a fact won&#x27;t be reached during the process of the upgrade,
and then you likely need to disable writes during the upgrade depending on
your workload.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#conclusion&quot;&gt;#&lt;&#x2F;a&gt;
Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;You can avoid all of the above pain by using UUID fields instead of
auto-incrementing integers. These have the benefit of being unpredictable and
not leak information about the cardinality of the underlying table if you do end
up using them outside of the table (which you shouldn&#x27;t).&lt;&#x2F;p&gt;
&lt;p&gt;Thanks to &lt;a href=&quot;https:&#x2F;&#x2F;incident.io&#x2F;blog&#x2F;one-two-skip-a-few&quot;&gt;this article&lt;&#x2F;a&gt; from the
wonderful folks at &lt;a href=&quot;https:&#x2F;&#x2F;incident.io&quot;&gt;Incident.io&lt;&#x2F;a&gt;, I am now aware of the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;German_tank_problem&quot;&gt;German tank problem&lt;&#x2F;a&gt;.
Well worth reading both the linked article, and the Wikipedia page, for more
reasons not to use auto-increment ID fields.&lt;&#x2F;p&gt;
</content>
            
        </entry>
    
    
        <entry xml:lang="en">
            <title>Getting an Autism Diagnosis</title>
            <published>2023-03-02T00:00:00+00:00</published>
            <updated>2023-03-02T00:00:00+00:00</updated>
            <author>
            <name>Unknown</name>
            </author>
            <link rel="alternate" href="https://old.samwho.dev/blog/getting-an-autism-diagnosis/" type="text/html"/>
            <id>https://old.samwho.dev/blog/getting-an-autism-diagnosis/</id>
            
            <content type="html">&lt;p&gt;On the 3rd of March 2022, we received a letter informing us that our eldest son,
Max, has Autism Spectrum Disorder. The letter was the end result of a long
process.  I’m going to talk about that process from start to finish, in as much
detail as I can.&lt;&#x2F;p&gt;
&lt;p&gt;This post would not have been possible without my wife&#x27;s dedication to our 2
children, her persistence in the face of long odds, and her diligent note
taking. Sophie, I love you.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max-autism-diagnosis.jpeg&quot; alt=&quot;A photograph of a letter explaining that our son, Max, has Autism Spectrum Disorder and Speech and Language difficulties&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;prologue&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#prologue&quot;&gt;#&lt;&#x2F;a&gt;
Prologue&lt;&#x2F;h2&gt;
&lt;p&gt;This post spiritually follows on from &lt;a href=&quot;&#x2F;blog&#x2F;having-a-baby&#x2F;&quot;&gt;this one&lt;&#x2F;a&gt;. I ended
that post by saying I’d like to write another post about the first months of
parenthood. That never happened, because the first months of parenthood are an
extreme test of patience and resolve.&lt;&#x2F;p&gt;
&lt;p&gt;Being new parents, we didn’t know what we were doing. Max was irritable,
difficult to get to sleep, and dropped down to the 9th percentile for weight.
This last piece of information was a shock to us, and to our health visitor, and
led to the revelation that Sophie wasn’t producing enough breastmilk. Nobody’s
fault, just the way it was.&lt;&#x2F;p&gt;
&lt;p&gt;To tell the truth, this was a relief. After we switched to formula feeding,
Max’s temperament changed almost overnight. He was content, he slept better, I
was able to help with feeding, and Sophie’s nipples were able to heal.&lt;&#x2F;p&gt;
&lt;p&gt;Max was 9 months old when the UK went into its first full lockdown of the
COVID-19 pandemic on March 26th 2020. The week before the lockdown was
announced, we had visited a local nursery and been given forms to fill in to
confirm Max’s attendance. We were excited to get him spending time with kids his
own age, and we were looking forward to getting some time off from parenting.&lt;&#x2F;p&gt;
&lt;p&gt;Instead, we all had to stay home 24&#x2F;7 by law. I was in the fortunate position
to already be working from home, and working in an industry that was relatively
unaffected by the pandemic. But none of this helped Max’s social development.&lt;&#x2F;p&gt;
&lt;p&gt;I tell you all of this because it’s relevant to Max’s diagnosis. While we got
his diagnosis earlier than most, a fact we are ever grateful for, it did take
longer than it would have had there been no pandemic. We attributed a lot of his
behaviour to having lived most of his life in lockdown.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-we-realised-max-was-different&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#how-we-realised-max-was-different&quot;&gt;#&lt;&#x2F;a&gt;
How we realised Max was different&lt;&#x2F;h2&gt;
&lt;p&gt;Max had his first “settling in” session at nursery on February 8th 2021. These
are short sessions, often only a few hours long, designed to ease your child in
to the nursery setting.  Max’s first settling in session didn’t go very well, a
fact that when taken in isolation isn&#x27;t unusual. He spent the majority of the
time screaming, and we ended up cutting it short.&lt;&#x2F;p&gt;
&lt;p&gt;Despite this, Sophie and I settled into a good rhythm with nursery. Max went
there twice a week. It was a good balance between cost, us getting time off, and
Max getting time with his peers. But Max wasn’t taking to it, and one evening a
member of staff took Sophie to one side and said Max “isn’t where we expect him
to be developmentally.”&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s hard to describe how this made me feel. Is this our fault? Are we not
parenting well enough?&lt;&#x2F;p&gt;
&lt;p&gt;Nursery&#x27;s concerns were that Max screams a lot, can’t follow instructions, and
his speech was less developed than his peers. They suggested it could be Max’s
hearing, and they recommended we talk to our GP to set up a hearing test. We
called our GP and had a frustrating conversation in which he asked us if &lt;em&gt;we&lt;&#x2F;em&gt;
think Max has problems hearing.  We explained that we had been recommended to
get a hearing test by his nursery.  But did &lt;em&gt;we&lt;&#x2F;em&gt; think he had problems hearing?
I didn’t think Max had any problems hearing, but I didn’t want to say that
because I am not a medical professional.&lt;&#x2F;p&gt;
&lt;p&gt;Nursery also recommended we contact our health visitor to ask for a
developmental review. In our area, kids used to go through a developmental
review at 2 years old. This changed in recent years, and it’s done at 3 years
old now. The review is made up of questions that gauge things your child can and
cannot do. At the end, you get a score. If you want to see what’s on it, you can
search “ASQ:3 24 months” and you’ll find loads of PDFs, all very similar.&lt;&#x2F;p&gt;
&lt;p&gt;Max didn’t do well at this, we had to say that he wasn’t able to do most of the
things they asked about. Because of his low score, we did another questionnaire
called the ASQ:SE:2. This one focuses on social and emotional development.
Again, Max scored low. It was the result of these two tests that led our health
visitor to refer us to our local council’s special educational needs and
disability (SEND) team. This happened on the 7th May 2021.&lt;&#x2F;p&gt;
&lt;p&gt;This referral included appointments with a paediatrician (which we were told
would take a few months, but actually ended up taking almost a full year),
speech and language therapist, and the SEND team themselves. The 7th of May was
the first point at which it felt “serious,” and we started to suspect he may be
autistic.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;jumping-through-all-the-hoops&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#jumping-through-all-the-hoops&quot;&gt;#&lt;&#x2F;a&gt;
Jumping through all the hoops&lt;&#x2F;h2&gt;
&lt;p&gt;On the 12th of August we had our appointment with the SEND team.  We’ll call her
Janet. It took place at nursery, and the day before it Janet had been at nursery
to spend time with Max and observe his behaviour. I remember messaging my boss
saying I need to be away from work for “an hour or so.” The meeting lasted 4
hours. It was obvious that Janet had spent a lot of time with Max, and had taken
detailed notes.&lt;&#x2F;p&gt;
&lt;p&gt;It was in this meeting that we asked “do you think Max is autistic?” Janet said
yes, he probably is. We had asked other people this same question, because it
had been on our mind since the ASQ, but everybody had been cagey about it. “Oh I
couldn’t say”, “I’m not qualified to make that diagnosis”, etc.  We appreciated
how forthcoming Janet was with us, and the risk she took personally being open
about it. She confessed in us later that a lot of parents don’t like hearing
that their child might be autistic, so she wasn’t surprised that most people
didn’t want to say.&lt;&#x2F;p&gt;
&lt;p&gt;After this meeting, Janet referred us to the Early Years SEND panel. It was
decided by them that Max had special needs. It’s important to note at this point
that we didn’t have an autism diagnosis. Help is based on need, not diagnosis.
Autism or not, Max needed help with his development and our local council would
give us that help regardless. Janet even went as far as to say that the
diagnosis is irrelevant to the SEND team, he’ll get the help he needs based on
what they observe.&lt;&#x2F;p&gt;
&lt;p&gt;On the 26th of August 2021 we had our first speech and language therapy (SLT)
appointment. This was an introductory session, Max played with some toy cars
while we spoke about his behaviours. One of the things we took away from this
appointment was to put Max&#x27;s toys into clear plastic containers that he would
need to ask us to open for him. This helps to cement the need for communication.
We still do that to this day, and we do believe it has helped.&lt;&#x2F;p&gt;
&lt;p&gt;On the 13th of September 2021, our special needs practitioner got in touch with
us for the first time. We’ll call her Fay. She arranged “play sessions” with
Max, these happened every few weeks from 22nd of September 2021 to 23rd of
September 2022. In these sessions, Fay presents Max with toys designed to test
him in different ways. Some of them require him to match colours, some of them
shapes, some of them are things you play with with another person, and some are
toys you aren’t meant to touch at all. All of these test how he reacts to
situations, how focused he is, how well he appreciates and accepts playing with
others.&lt;&#x2F;p&gt;
&lt;p&gt;Something those play sessions taught me is that playing with children is a
skill. Fay was able to get Max to play in ways we would have said were
impossible without seeing it for ourselves. She was able to get him to do things
when she said so, and more crucially to not do things he obviously wanted to do.
He responded to her extremely well, and it was a joy to watch her work with him.&lt;&#x2F;p&gt;
&lt;p&gt;We had heard it previously from Janet, but Fay confirmed it: Max has no
difficulty learning. The way he learns is different to most other kids, though,
and will benefit from a more tailored approach. Looking back, it is probably
around this time we started forming our opinion that Max should attend a special
needs school.&lt;&#x2F;p&gt;
&lt;p&gt;On the 30th of September 2021 we had Max&#x27;s first hearing test. The way that they
wanted to test Max&#x27;s hearing was with a set of stacking cups. The doctor would
demonstrate making a noise, then putting a cup onto the stack. Then she would
make the noise again and add another cup. Then she would try and get the child
to do the same. Max, however, wasn&#x27;t at the level of understanding required to
complete this test.&lt;&#x2F;p&gt;
&lt;p&gt;The backup test that she had involved a shelf of toys. The shelf was a grid,
like a set of IKEA Kallax shelves, and in each square was a toy that could make
a noise. The doctor would trigger each toy to make a noise and the idea was for
Max to look at the toy that made the noise. Unfortunately, Max was terrified of
the toys and screamed uncontrollably upon seeing them.&lt;&#x2F;p&gt;
&lt;p&gt;After this, the test was rescheduled for January 10th 2022. This time they tried
to have him listen to a cartoon on the television while they put a sensor in his
ear to take some measurements. He refused to let them put the device in his ear
long enough to get any readings. They tried the first set of tests again, but he
reacted the same way he did before. A third test was scheduled on February 3rd
2022.&lt;&#x2F;p&gt;
&lt;p&gt;This time they wanted to try and do the test while Max was asleep, but we
weren&#x27;t able to get Max to sleep at the time of the appointment. However, to
everyone&#x27;s surprise, he went in to the doctor&#x27;s office and did the stacked cup
test immediately without prompting. He passed with flying colours, ruling out
that hearing was causing his language difficulties. To this day we don&#x27;t know
what changed.&lt;&#x2F;p&gt;
&lt;p&gt;On the 17th of February 2022, 6 months after the first appointment, we had our
second SLT appointment. We had to chase them up to get this to happen, as we had
not heard back from them. In this appointment we learned about &quot;transition
objects&quot;, objects to help children go from one activity to another. We used
bubbles to help get Max to get in the bath, and a toy game controller to help
get him in to the car. He still uses the toy controller today, though he has
grown to enjoy bath time enough to not need the bubbles.&lt;&#x2F;p&gt;
&lt;p&gt;On the same day, in the afternoon, we got a phone call telling us that there had
been a short-notice cancellation with the paediatrician and would we like to do
our appointment on the 20th of February? You&#x27;re damn right we would! We had been
waiting for this appointment since May 2021, and had heard from friends that
waiting over a year was common. Some people wait more than 2 years. To get seen
in less than a year is rare.&lt;&#x2F;p&gt;
&lt;p&gt;Janet, our SEND coordinator, had compiled all of the paperwork from our other
appointments and sent them to the paediatrician. She had also let the
paediatrician know that we were receptive to a diagnosis (not all parents are).
Unfortunately, for whatever reason, this documentation didn&#x27;t get to the
paediatrician ready for the appointment. The paediatrician had moved from
another area and wasn&#x27;t fully set up with her email yet.&lt;&#x2F;p&gt;
&lt;p&gt;However, with what Sophie was able to find on her phone, and after observing Max
for about an hour, the paediatrician told us she felt comfortable giving him a
diagnosis of autism there and then, with an official letter to follow.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;wrapping-up&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#wrapping-up&quot;&gt;#&lt;&#x2F;a&gt;
Wrapping up&lt;&#x2F;h2&gt;
&lt;p&gt;Getting an autism diagnosis before the age of 3 is uncommon, and I have to
express appreciation for everyone involved in the process. While the help given
to children should be based on needs alone, we have found it helpful to have a
recognised diagnosis.&lt;&#x2F;p&gt;
&lt;p&gt;What I plan to write about next is the process we went through to get Max in to
a special needs school, a process which came to an end just a few weeks ago.  We
are ecstatic.&lt;&#x2F;p&gt;
</content>
            
        </entry>
    
    
        <entry xml:lang="en">
            <title>I finally figured out how to take notes!</title>
            <published>2022-02-14T00:00:00+00:00</published>
            <updated>2022-02-14T00:00:00+00:00</updated>
            <author>
            <name>Unknown</name>
            </author>
            <link rel="alternate" href="https://old.samwho.dev/blog/note-taking/" type="text/html"/>
            <id>https://old.samwho.dev/blog/note-taking/</id>
            
            <content type="html">&lt;p&gt;I’ve never been good at taking notes. I’ve tried. Oh boy, have I tried. Name a
piece of note taking software, odds are I’ve tried it. I’ve even tried going old
school with pen and paper. Nothing sticks.&lt;&#x2F;p&gt;
&lt;p&gt;Until recently.&lt;&#x2F;p&gt;
&lt;p&gt;Some time ago, I learned about Apple’s
&lt;a href=&quot;https:&#x2F;&#x2F;apps.apple.com&#x2F;gb&#x2F;app&#x2F;shortcuts&#x2F;id1462947752&quot;&gt;Shortcuts&lt;&#x2F;a&gt; app. It’s an
app on iOS, iPadOS, and MacOS that allows you to automate actions between apps.
It’s a little like &lt;a href=&quot;https:&#x2F;&#x2F;ifttt.com&quot;&gt;IFTTT&lt;&#x2F;a&gt;. I played with it and made a few
fun things. I created a keyboard shortcut that could turn my lights on and off,
for example. I didn’t take it much further than that.&lt;&#x2F;p&gt;
&lt;p&gt;Since the start of the new year, I’ve been taking on more responsibility at
work. This has meant an increase in meetings, and an increase in me being
responsible for making sure things are moving forward. This means I often have
to follow up on things after a meeting, and I would sometimes forget to do this.
This would not do, I thought, and decided it was time to start taking meeting
notes.&lt;&#x2F;p&gt;
&lt;p&gt;I had some requirements in mind:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;I want to be able to tag notes. I’d like to track things like date, who was
there, what the key topics were, and be able to search based on these tags.&lt;&#x2F;li&gt;
&lt;li&gt;I need the ability to create action items, and be able to ask “what action
items have I not yet done?”&lt;&#x2F;li&gt;
&lt;li&gt;It has to be super easy. I want to be able to jump into a meeting and have my
meeting notes ready to go.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Turns out, combining Apple Shortcuts with &lt;a href=&quot;https:&#x2F;&#x2F;bear.app&quot;&gt;Bear&lt;&#x2F;a&gt; hits all of
these requirements.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;shortcuts&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#shortcuts&quot;&gt;#&lt;&#x2F;a&gt;
Shortcuts&lt;&#x2F;h2&gt;
&lt;p&gt;I have two Shortcuts I use to make my note taking life much easier:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;A shortcut that creates a meeting note.&lt;&#x2F;li&gt;
&lt;li&gt;A shortcut that opens or creates a daily “scratch” note, for note taking
outside of meetings.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The meeting note shortcut does the following:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Looks in my work calendar for the most recent meeting that started in the
last 30 minutes.&lt;&#x2F;li&gt;
&lt;li&gt;It then creates a note with the meeting title as the note title, and it adds
tags for each person who accepted the calendar invite. It also adds a tag for
the current date, my current location, and the current temperature outside. Just
a bit of fun.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I trigger this shortcut by typing cmd+ctrl+m. Any meeting I go in to, the first
thing I do while I’m waiting for people to arrive is hit that shortcut, the note
pops up a few seconds later, and I’m ready to take notes.&lt;&#x2F;p&gt;
&lt;p&gt;The daily scratch note shortcut is much simpler. It creates a note with the
current date as the title, and all of the same non-meeting-specific tags as the
meeting note: date, location, temperature. The only difference is it first
searches for a note with the current date as the title, and if it finds it it
opens that instead of creating a new one. I trigger this shortcut with
cmd+ctrl+s.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;shortcut.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;shortcut.png&quot; alt=&quot;My daily scratch note shortcut&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After a second or two, a note that looks like this opens up on my screen:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;note.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;note.png&quot; alt=&quot;A daily scratch note&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bear&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#bear&quot;&gt;#&lt;&#x2F;a&gt;
Bear&lt;&#x2F;h2&gt;
&lt;p&gt;Other than being a beautiful demonstration of not implementing every single
feature your user base asks for, the primary thing Bear excels at in my workflow
is TODO management.&lt;&#x2F;p&gt;
&lt;p&gt;At any point in any note, you can create a TODO. This manifests as a list item
with a checkbox, much like GitHub’s TODOs. You can have as many TODOs as you
want in a note, and Bear has a section of its navigation menu that will show you
all notes with outstanding TODOs.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;note-with-todo.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;note-with-todo.png&quot; alt=&quot;A daily scratch note with TODOs&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#conclusion&quot;&gt;#&lt;&#x2F;a&gt;
Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve been using this new system for about a week now, which is longer than I’ve
been able to stick with any other note taking system. Nothing else has ever felt
as natural to me as this does.&lt;&#x2F;p&gt;
&lt;p&gt;The key outcome, though, is that I feel more on top of things now. I’m not
dropping the ball on things people ask me to do in meetings. People don’t have
to chase me for things as much, which makes me feel good and I’m sure it makes
them feel good as well.&lt;&#x2F;p&gt;
</content>
            
        </entry>
    
    
        <entry xml:lang="en">
            <title>Adventures in Homelab: Part 1</title>
            <published>2021-05-02T00:00:00+00:00</published>
            <updated>2021-05-02T00:00:00+00:00</updated>
            <author>
            <name>Unknown</name>
            </author>
            <link rel="alternate" href="https://old.samwho.dev/blog/adventures-in-homelab-part-1/" type="text/html"/>
            <id>https://old.samwho.dev/blog/adventures-in-homelab-part-1/</id>
            
            <content type="html">&lt;p&gt;If you work in tech, and you use the cloud in any way, you&#x27;ve probably heard of
Kubernetes. It&#x27;s inescapable now, and there&#x27;s no shortage of takes on it.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve worked in a few companies that have used Kubernetes, but never been close
to it. I&#x27;ve used in-house tools that communicate with it, or CI&#x2F;CD systems that
deploy my code in to it automatically. This has left me not really knowing what
Kubernetes is or how it works.&lt;&#x2F;p&gt;
&lt;p&gt;That changes now.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m embarking on a journey to create a production-ready Kubernetes cluster in my
own home.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-s-in-this-post&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#what-s-in-this-post&quot;&gt;#&lt;&#x2F;a&gt;
What&#x27;s in this post&lt;&#x2F;h2&gt;
&lt;p&gt;At the end of this post I will have shown you:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;How I installed Arch Linux on 3 Raspberry Pi 4Bs and got them ready to be kubelets&lt;&#x2F;li&gt;
&lt;li&gt;How I bootstrapped a bare metal Kubernentes cluster on those Raspberry Pis&lt;&#x2F;li&gt;
&lt;li&gt;How I set up pod networking in the cluster&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;things-i-bought&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#things-i-bought&quot;&gt;#&lt;&#x2F;a&gt;
Things I bought&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;ve also wanted to slide down the &lt;a href=&quot;https:&#x2F;&#x2F;reddit.com&#x2F;r&#x2F;homelab&quot;&gt;&#x2F;r&#x2F;homelab&lt;&#x2F;a&gt; rabbit hole for a while, so
here&#x27;s what I bought to get started:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;3x &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.co.uk&#x2F;gp&#x2F;product&#x2F;B08M39828H&#x2F;ref=ppx_yo_dt_b_asin_title_o08_s04?ie=UTF8&amp;amp;psc=1&quot;&gt;Raspberry Pi 4 model B&lt;&#x2F;a&gt; with &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.co.uk&#x2F;gp&#x2F;product&#x2F;B07VKF1CK8&#x2F;ref=ppx_yo_dt_b_asin_title_o08_s00?ie=UTF8&amp;amp;psc=1&quot;&gt;power supplies&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.co.uk&#x2F;gp&#x2F;product&#x2F;B08GYKNCCP&#x2F;ref=ppx_yo_dt_b_asin_title_o08_s04?ie=UTF8&amp;amp;psc=1&quot;&gt;SD cards&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;A &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.co.uk&#x2F;gp&#x2F;product&#x2F;B08Q8MTGHS&#x2F;ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&amp;amp;psc=1&quot;&gt;rack mount for the Raspberry Pis&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;A &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.co.uk&#x2F;gp&#x2F;product&#x2F;B013PGHUZS&#x2F;ref=ppx_yo_dt_b_asin_title_o09_s00?ie=UTF8&amp;amp;psc=1&quot;&gt;12u 19&quot; cabinet&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;A &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.co.uk&#x2F;gp&#x2F;product&#x2F;B07DFBX347&#x2F;ref=ppx_yo_dt_b_asin_title_o08_s02?ie=UTF8&amp;amp;psc=1&quot;&gt;16 PoE port gigabit ethernet switch&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;A &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.co.uk&#x2F;gp&#x2F;product&#x2F;B08NXD85CK&#x2F;ref=ppx_yo_dt_b_asin_title_o05_s00?ie=UTF8&amp;amp;psc=1&quot;&gt;rack mountable power strip&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;A &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.co.uk&#x2F;gp&#x2F;product&#x2F;B008X3JHJQ&#x2F;ref=ppx_yo_dt_b_asin_title_o07_s00?ie=UTF8&amp;amp;psc=1&quot;&gt;rack mountable shelf&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Some &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.co.uk&#x2F;gp&#x2F;product&#x2F;B004FEGBTQ&#x2F;ref=ppx_yo_dt_b_asin_title_o08_s03?ie=UTF8&amp;amp;psc=1&quot;&gt;teeny weeny network cables&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Here&#x27;s what it all looks like when put together:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;localkube-1.jpg&quot; alt=&quot;My home server rack from top to bottom: the 3 raspberry pis mounted in their mounting bracket, the PoE switch below them with patch cables running to each pi, and the shelf below that holding a UPS and a NAS&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Also pictured here is the shelf, which is holding a &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.co.uk&#x2F;gp&#x2F;product&#x2F;B07BZCD927&#x2F;ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;amp;psc=1&quot;&gt;UPS&lt;&#x2F;a&gt; on the left and a
&lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.co.uk&#x2F;gp&#x2F;product&#x2F;B075DDZ894&#x2F;ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;amp;psc=1&quot;&gt;NAS&lt;&#x2F;a&gt; on the right. I had those things already, so didn&#x27;t list them as part
of what I bought for this project. While the UPS is optional, the NAS is quite
critical to my setup. It will eventually host all of the persistent data for
my cluster. More about this in the 2nd part of this series.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;preparing-the-pis&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#preparing-the-pis&quot;&gt;#&lt;&#x2F;a&gt;
Preparing the Pis&lt;&#x2F;h2&gt;
&lt;p&gt;The first step is to get an OS running on the Raspberry Pis. While the official
documentation on &lt;a href=&quot;https:&#x2F;&#x2F;kubernetes.io&#x2F;docs&#x2F;setup&#x2F;production-environment&#x2F;tools&#x2F;kubeadm&#x2F;create-cluster-kubeadm&#x2F;&quot;&gt;creating a bare metal Kubernetes cluster&lt;&#x2F;a&gt; recommends using
a deb&#x2F;rpm-compatible Linux distribution, I&#x27;m a long-time fan of Arch Linux.
Surely I can&#x27;t be the first person to want to do this on Arch?&lt;&#x2F;p&gt;
&lt;p&gt;Fortunately, I&#x27;m not. Morten Linderud, part of the Arch Linux security team, has
written a &lt;a href=&quot;https:&#x2F;&#x2F;linderud.dev&#x2F;blog&#x2F;kubernetes-in-arch-linux&#x2F;&quot;&gt;great blog post&lt;&#x2F;a&gt; on getting a bare metal Kubernetes cluster
working using Arch Linux. There&#x27;s only one small gotcha: he didn&#x27;t do it on
Raspberry Pis.&lt;&#x2F;p&gt;
&lt;p&gt;Before running through the steps in his blog post, we need to get Arch running
on the Pis. I followed &lt;a href=&quot;https:&#x2F;&#x2F;archlinuxarm.org&#x2F;platforms&#x2F;armv8&#x2F;broadcom&#x2F;raspberry-pi-4&quot;&gt;this guide&lt;&#x2F;a&gt; from the official Arch Linux website,
which worked perfectly. I followed the ARMv7 installation guide because the
disclaimer for AArch64 put me off a little. This decision hasn&#x27;t hurt me so far,
though I have occasionally had to look harder for docker images built for ARM
and not ARM64 (thanks, Apple).&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m going to use &lt;code&gt;kubeadm&lt;&#x2F;code&gt; to bootstrap my cluster, and while &lt;code&gt;kubeadm&lt;&#x2F;code&gt; is an
officially supported package in the Arch Linux repos, there&#x27;s no ARM build of
it. There is, however, an ARM build &lt;a href=&quot;https:&#x2F;&#x2F;aur.archlinux.org&#x2F;packages&#x2F;kubeadm-bin&#x2F;&quot;&gt;in the AUR&lt;&#x2F;a&gt;. I installed &lt;a href=&quot;https:&#x2F;&#x2F;aur.archlinux.org&#x2F;packages&#x2F;yay&#x2F;&quot;&gt;yay&lt;&#x2F;a&gt; as
my preferred AUR tool.&lt;&#x2F;p&gt;
&lt;p&gt;To save some time, I&#x27;ll tell you I needed to install all of the following on
each pi:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;yay&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;S&lt;&#x2F;span&gt; kubeadm kubelet crictl conntrack-tools ethtool ebtables cni-plugins containerd socat&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A lot of them came up during the &lt;code&gt;kubeadm init&lt;&#x2F;code&gt; process. It runs a set of
&quot;preflight checks&quot; that require you to install necessary binaries. It also
checks to make sure your system has various capabilities, and one of these
was missing for me: memory cgroups. I had to add the following onto the end
of &lt;code&gt;&#x2F;boot&#x2F;cmdline.txt&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;cgroup_enable=memory
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And reboot. It also warned me that the &lt;code&gt;hugetlb&lt;&#x2F;code&gt; cgroup wasn&#x27;t enabled, but it
was an optional dependency and I decided to ignore it. This hasn&#x27;t bitten me so
far.&lt;&#x2F;p&gt;
&lt;p&gt;The last thing I did was set the hostname of each of the nodes. Modify
&lt;code&gt;&#x2F;etc&#x2F;hostname&lt;&#x2F;code&gt; and name the nodes as you see fit. I used &lt;code&gt;kubernetes-master&lt;&#x2F;code&gt;,
&lt;code&gt;kubernetes-worker-1&lt;&#x2F;code&gt;, and &lt;code&gt;kubernetes-worker-2&lt;&#x2F;code&gt;. I also gave them static IPs in
my local network, and DNS names to make communicating with them easier.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bootstrapping-the-cluster&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#bootstrapping-the-cluster&quot;&gt;#&lt;&#x2F;a&gt;
Bootstrapping the cluster&lt;&#x2F;h2&gt;
&lt;p&gt;Step 1 to bootstrapping a cluster is to set up your master node. The Kubernetes
project ships a tool called &lt;code&gt;kubeadm&lt;&#x2F;code&gt; (Kubernetes admin) that makes this very
easy. I ran the following:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubeadm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; init&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;pod-network-cidr&lt;&#x2F;span&gt; 10.244.0.0&#x2F;16&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;upload-certs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The flag &lt;code&gt;--pod-network-cidr&lt;&#x2F;code&gt; is the desired subnet you want pods to live in. I
chose something that&#x27;s very different to my home network so I would be able to
distinguish them.  The flag &lt;code&gt;--upload-certs&lt;&#x2F;code&gt; I&#x27;m not really sure about. Martin
Linderud uses it in his blog post, so I did as well. From reading the
documentation on the flag it looks like I didn&#x27;t need it, so try without if
you&#x27;re feeling adventurous.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;kubeadm init&lt;&#x2F;code&gt; runs a set of preflight checks first. It&#x27;s possible you will fail
some of those checks. In that case, make sure you do some searching to figure
out what&#x27;s wrong and fix it before continuing.&lt;&#x2F;p&gt;
&lt;p&gt;When &lt;code&gt;kubeadm init&lt;&#x2F;code&gt; finishes, you&#x27;ll see output that looks like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Your Kubernetes control-plane has initialized successfully!
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;To start using your cluster, you need to run the following as a regular user:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  mkdir -p $HOME&#x2F;.kube
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  sudo cp -i &#x2F;etc&#x2F;kubernetes&#x2F;admin.conf $HOME&#x2F;.kube&#x2F;config
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  sudo chown $(id -u):$(id -g) $HOME&#x2F;.kube&#x2F;config
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;You should now deploy a Pod network to the cluster.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Run &amp;quot;kubectl apply -f [podnetwork].yaml&amp;quot; with one of the options listed at:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  &#x2F;docs&#x2F;concepts&#x2F;cluster-administration&#x2F;addons&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;You can now join any number of machines by running the following on each node
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;as root:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  kubeadm join &amp;lt;control-plane-host&amp;gt;:&amp;lt;control-plane-port&amp;gt; --token &amp;lt;token&amp;gt; --discovery-token-ca-cert-hash sha256:&amp;lt;hash&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Save that &lt;code&gt;kubeadm join&lt;&#x2F;code&gt; command, you&#x27;ll need it in a few minutes.&lt;&#x2F;p&gt;
&lt;p&gt;It was at this point that I also copied the &lt;code&gt;~&#x2F;.kube&#x2F;config&lt;&#x2F;code&gt; file to my main
development machine and closed the SSH connection to my master node.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pod-networking&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#pod-networking&quot;&gt;#&lt;&#x2F;a&gt;
Pod networking&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;now-this-is-pod-networking.jpg&quot; alt=&quot;Anakin Skywalker pod-racing with the caption &amp;quot;Now this is pod networking!&amp;quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Pod networking has come up a couple of times now, but what is it?&lt;&#x2F;p&gt;
&lt;p&gt;A Kubernetes cluster consists of 0-n nodes. A node is a physical machine running
the &lt;code&gt;kubelet&lt;&#x2F;code&gt; daemon configured to be a part of your cluster. On a node, 0-n
pods can be running. A pod is a collection of 1-n containers that share a local
network. They&#x27;re called pods as a reference to a pod of dolphins, according to
the book &lt;a href=&quot;https:&#x2F;&#x2F;www.oreilly.com&#x2F;library&#x2F;view&#x2F;kubernetes-up-and&#x2F;9781492046523&#x2F;&quot;&gt;Kubernetes: Up and Running&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Because the networks that Kubernetes clusters are deployed in are extremely
varied (from cloud providers to datacenters to home networks), and needs will
differ dramatically, Kubernetes doesn&#x27;t ship clusters with a way for pods to
communicate with other pods by default. You need to select a third-party
solution that fits your needs.&lt;&#x2F;p&gt;
&lt;p&gt;Deciding what pod networking solution is best for you is outside of the scope
of this article, I&#x27;ll just say that I went with &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;flannel-io&#x2F;flannel&quot;&gt;flannel&lt;&#x2F;a&gt;. It sounded simple
and just sorts out networking between pods without any extra fancy features.
Its limitations, primarily that nodes must be on the same physical network to
each other, was not a concern for me.&lt;&#x2F;p&gt;
&lt;p&gt;Normally, you would install flannel like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; apply&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;f&lt;&#x2F;span&gt; https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;coreos&#x2F;flannel&#x2F;master&#x2F;Documentation&#x2F;kube-flannel.yml&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But I found that this didn&#x27;t work for me. There were two reasons:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;I was missing the &lt;code&gt;cni-plugins&lt;&#x2F;code&gt; package&lt;&#x2F;li&gt;
&lt;li&gt;The default backend flannel uses, &lt;code&gt;vxlan&lt;&#x2F;code&gt;, didn&#x27;t work for some reason&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;While 1 took some time to figure out, largely by doing lots of
&lt;code&gt;kubectl describe pod&lt;&#x2F;code&gt; commands, it was a simple fix once I saw the error
message.&lt;&#x2F;p&gt;
&lt;p&gt;2, however, was tricky. Pod to pod communication by pure pod IP address worked
fine, but any communication through a cluster IP address hanged indefinitely.
After a lot of searching, I found someone suggesting to switch away from
flannel&#x27;s default &lt;code&gt;vxlan&lt;&#x2F;code&gt; backend, to the &lt;code&gt;host-gw&lt;&#x2F;code&gt; backend.&lt;&#x2F;p&gt;
&lt;p&gt;What does all of this mean? Fuck if I know. All I know is that it fixed the
problem I was having. If you download the flannel manifest from the command
above and find the &lt;code&gt;ConfigMap&lt;&#x2F;code&gt; called &lt;code&gt;kube-flannel-cfg&lt;&#x2F;code&gt;, modify the bit called
&lt;code&gt;net-conf.json&lt;&#x2F;code&gt; so that it looks like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json z-code&quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Network&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;10.244.0.0&#x2F;16&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Backend&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Type&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;host-gw&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Last but not least, I found that I had to restart my master node after all of
these changes. It takes a minute or two to boot back up, but when it did
I was greeted with this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ kubectl get nodes
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;NAME                        STATUS   ROLES                  AGE     VERSION
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;kubernetes-master.local     Ready    control-plane,master   14m     v1.21.0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;adding-the-worker-nodes&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#adding-the-worker-nodes&quot;&gt;#&lt;&#x2F;a&gt;
Adding the worker nodes&lt;&#x2F;h2&gt;
&lt;p&gt;Remember that &lt;code&gt;kubeadm join&lt;&#x2F;code&gt; command I said to save for later? Now is later.
Adding nodes to your cluster is as simple as running that join command on each
node.&lt;&#x2F;p&gt;
&lt;p&gt;One bit of weirdness I experienced is that after newly joining a node to the
cluster, it would get stuck in the &lt;code&gt;NotReady&lt;&#x2F;code&gt; state. This resolved itself after
rebooting each node. Not sure what that&#x27;s all about, I&#x27;m assuming network
voodoo with flannel.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ kubectl get nodes
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;NAME                        STATUS   ROLES                  AGE     VERSION
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;kubernetes-master.local     Ready    control-plane,master   20m     v1.21.0
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;kubernetes-worker-1.local   Ready    &amp;lt;none&amp;gt;                 2m      v1.21.0
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;kubernetes-worker-2.local   Ready    &amp;lt;none&amp;gt;                 1m      v1.21.0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#conclusion&quot;&gt;#&lt;&#x2F;a&gt;
Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;So now we have a working bare metal Kubernetes cluster, we&#x27;re ready to start
running things on it. We still have a long way to go until our cluster can run
any kind of workload we want. We&#x27;ll need to handle load balancing, persistent
storage, and ingress resources. All of that is going to be in part 2.&lt;&#x2F;p&gt;
&lt;p&gt;We have an even longer way to go until we could call this a production-ready
cluster. The main thing missing for that is that we&#x27;d need to run 3 master
nodes, and this is something I want to explore in a future post.&lt;&#x2F;p&gt;
</content>
            
        </entry>
    
    
        <entry xml:lang="en">
            <title>Simple Complex Easy Hard</title>
            <published>2021-04-18T00:00:00+00:00</published>
            <updated>2021-04-18T00:00:00+00:00</updated>
            <author>
            <name>Unknown</name>
            </author>
            <link rel="alternate" href="https://old.samwho.dev/blog/simple-complex-easy-hard/" type="text/html"/>
            <id>https://old.samwho.dev/blog/simple-complex-easy-hard/</id>
            
            <content type="html">&lt;p&gt;You might have noticed the last time you were doing chores or tackling a
tricky problem at work, that when something is hard it&#x27;s not always hard in
the same way. The hard you experience when doing chores, that mindnumbing ,
I-can&#x27;t-be-bothered hard, is different to the hard you might experience when
debugging an elusive bug in a distributed system.&lt;&#x2F;p&gt;
&lt;p&gt;Why?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-2-axes-of-difficulty&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#the-2-axes-of-difficulty&quot;&gt;#&lt;&#x2F;a&gt;
The 2 axes of difficulty&lt;&#x2F;h2&gt;
&lt;p&gt;There are many things that determine whether a task is difficult or not, but you
can make a start on getting more granular by splitting difficulty into two axes:
simple-complex and easy-hard.&lt;&#x2F;p&gt;
&lt;p&gt;What&#x27;s the difference?&lt;&#x2F;p&gt;
&lt;p&gt;A sudoku puzzle is &lt;em&gt;complex&lt;&#x2F;em&gt;. It depends on your skill at sudoku puzzles, and
you&#x27;re able to do more complex sudoku puzzles the more you practice and hone
this skill. A task is complex when the number of people that &lt;em&gt;could&lt;&#x2F;em&gt; do it
tends toward zero. If a lot of people could do it, that would make it
&lt;em&gt;simple&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The other scale measures how much effort must be expended to complete the
task. If you&#x27;re put off by how much effort will be involved, it&#x27;s likely
&lt;em&gt;hard&lt;&#x2F;em&gt;. Something is hard when the number of people that are willing to put
the effort in tends toward zero.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-does-this-matter&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#why-does-this-matter&quot;&gt;#&lt;&#x2F;a&gt;
Why does this matter?&lt;&#x2F;h2&gt;
&lt;p&gt;This distinction can help you with time estimations. Complexity is one of the
key things that introduces uncertainty in to estimating how long a task will
take. It&#x27;s not unusual to get half way through a sudoku puzzle and realise
you&#x27;ve made a mistake somewhere, and need to backtrack. On the other hand,
you know quite accurately how long it&#x27;s going to take you to mow the lawn.&lt;&#x2F;p&gt;
&lt;p&gt;Adding this vocabulary to your work tasks can help people to understand what
to expect. A simple-easy task is likely to be predictably quick. A
simple-hard task predictably long. A complex-hard task is anyone&#x27;s guess, and
may even be worth breaking in to several smaller tasks.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;other-examples&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#other-examples&quot;&gt;#&lt;&#x2F;a&gt;
Other examples&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;simple-complex-easy-hard.png&quot; alt=&quot;Image showing 2 axes crossing in the middle, X axis is simple-complex, Y-axis is easy-hard, with a variety of examples of tasks. Looking after a newborn is simple hard, mowing the lawn is simple-middle, putting a mug in the dishwasher is easy-simple, wiring a plug is easy-middle, tracking down a bug that doesn&amp;#39;t happen when you attach a debugger is complex-hard&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m sure you might disagree with some of these, I didn&#x27;t spend an enormous
amount of time thinking about them. If you have other examples, I&#x27;d love to hear
about them.&lt;&#x2F;p&gt;
</content>
            
        </entry>
    
</feed>
