<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://guiyuanju.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://guiyuanju.github.io/" rel="alternate" type="text/html" /><updated>2026-04-03T18:19:11+00:00</updated><id>https://guiyuanju.github.io/feed.xml</id><title type="html">Keien</title><subtitle>My Blog</subtitle><entry><title type="html">“Generic” Vector in C From Scratch</title><link href="https://guiyuanju.github.io/generic-vector-in-c.html" rel="alternate" type="text/html" title="“Generic” Vector in C From Scratch" /><published>2026-02-02T00:00:00+00:00</published><updated>2026-02-02T00:00:00+00:00</updated><id>https://guiyuanju.github.io/Generic-Vector-in-C</id><content type="html" xml:base="https://guiyuanju.github.io/generic-vector-in-c.html"><![CDATA[<p><a href="https://github.com/guiyuanju/vector">github repo</a></p>

<p>A vector is a dynamically growable array allocated on heap, the concept is similar to <code class="language-plaintext highlighter-rouge">ArrayList</code> in Java or <code class="language-plaintext highlighter-rouge">slice</code> in Go (slice is actually a little different).</p>

<p>C lacks such convenient data structure, but we can build one with an easy to use interface by ourselves.</p>

<p>First define the Vec structure, a dynamic array should have a <code class="language-plaintext highlighter-rouge">len</code> indicating the actual length of data in the underlying storage, <code class="language-plaintext highlighter-rouge">cap</code> tells us the length of the storage, and <code class="language-plaintext highlighter-rouge">size</code> is quite interesting here, which represents the byte size of a single data element we store in this vector, because C doesn’t have generic, and there is no type info during runtime, we need some way to know our type, so that we can retrieve the data from the bytes stored in storage using its byte size, and at last, we have the <code class="language-plaintext highlighter-rouge">data</code>, which is the underlying storage to store all our elements, in bytes.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
  <span class="kt">size_t</span> <span class="n">len</span><span class="p">;</span>
  <span class="kt">size_t</span> <span class="n">cap</span><span class="p">;</span>
  <span class="kt">size_t</span> <span class="n">size</span><span class="p">;</span>  <span class="c1">// size of an element</span>
  <span class="kt">char</span> <span class="n">data</span><span class="p">[];</span>  <span class="c1">// flexible array member</span>
<span class="p">}</span> <span class="n">Vec</span><span class="p">;</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">data</code> is a flexible array member of this structure, it doesn’t occupy any space, just a name that we can use to get the pointer to the end of our Vec structure. We have a special way to allocate the storage: we treat our Vec structure as a header, and we allocate more space than a Vec structure needs, the extra space is used for the actual storage.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span><span class="o">*</span> <span class="nf">vec_new</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">len</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">cap</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">size</span><span class="p">)</span> <span class="p">{</span>
  <span class="c1">// malloc the size of Vec and size * cap, that is the initial space specified</span>
  <span class="n">Vec</span><span class="o">*</span> <span class="n">vector</span> <span class="o">=</span> <span class="p">(</span><span class="n">Vec</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="n">offsetof</span><span class="p">(</span><span class="n">Vec</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span> <span class="o">+</span> <span class="n">size</span> <span class="o">*</span> <span class="n">cap</span><span class="p">);</span>
  <span class="n">vector</span><span class="o">-&gt;</span><span class="n">len</span> <span class="o">=</span> <span class="n">len</span><span class="p">;</span>
  <span class="n">vector</span><span class="o">-&gt;</span><span class="n">cap</span> <span class="o">=</span> <span class="n">cap</span><span class="p">;</span>
  <span class="n">vector</span><span class="o">-&gt;</span><span class="n">size</span> <span class="o">=</span> <span class="n">size</span><span class="p">;</span>
  <span class="c1">// return the data, instead of the Vec</span>
  <span class="k">return</span> <span class="p">(</span><span class="kt">void</span><span class="o">*</span><span class="p">)(</span><span class="n">vector</span><span class="o">-&gt;</span><span class="n">data</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Look at the <code class="language-plaintext highlighter-rouge">return (void*)(vector-&gt;data)</code>, the function is not returning a pointer to the <code class="language-plaintext highlighter-rouge">Vec</code>, but the <code class="language-plaintext highlighter-rouge">data</code> member, why do we do this? Because user now gets a real array of elements, not a custom type, which enables the familiar array index syntax like <code class="language-plaintext highlighter-rouge">data[i]</code>, without the need for a custom function like <code class="language-plaintext highlighter-rouge">vec_get(vec, idx)</code>, <code class="language-plaintext highlighter-rouge">vec_set(vec, idx, val)</code>, provides a simple interface.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span><span class="o">*</span> <span class="n">vec</span> <span class="o">=</span> <span class="n">vec_new</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">int</span><span class="p">));</span>
<span class="n">vec</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
</code></pre></div></div>

<p>We could define a macro <code class="language-plaintext highlighter-rouge">vnew</code> to simplify the interface further.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define vnew(type, len) vec_new(len, len, sizeof(type))
</span></code></pre></div></div>

<p>With <code class="language-plaintext highlighter-rouge">vnew</code> defined, we can use it as if we have generics in C.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span><span class="o">*</span> <span class="n">vec</span> <span class="o">=</span> <span class="n">vnew</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
<span class="n">vec</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
</code></pre></div></div>

<p>Okay, we have a fixed length array, how to make our vector growable? We need a function to actually do the job, below is a <code class="language-plaintext highlighter-rouge">vec_grow</code> function that takes a vector data and grow it.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span><span class="o">*</span> <span class="nf">vec_grow</span><span class="p">(</span><span class="kt">void</span><span class="o">*</span> <span class="n">vector</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">Vec</span><span class="o">*</span> <span class="n">header</span> <span class="o">=</span> <span class="n">vheader</span><span class="p">(</span><span class="n">vector</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">header</span><span class="o">-&gt;</span><span class="n">cap</span> <span class="o">&gt;=</span> <span class="mi">8</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">header</span><span class="o">-&gt;</span><span class="n">cap</span> <span class="o">+=</span> <span class="n">header</span><span class="o">-&gt;</span><span class="n">cap</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="n">header</span><span class="o">-&gt;</span><span class="n">cap</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">header</span> <span class="o">=</span> <span class="n">realloc</span><span class="p">(</span><span class="n">header</span><span class="p">,</span> <span class="n">offsetof</span><span class="p">(</span><span class="n">Vec</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span> <span class="o">+</span> <span class="n">header</span><span class="o">-&gt;</span><span class="n">cap</span> <span class="o">*</span> <span class="n">header</span><span class="o">-&gt;</span><span class="n">size</span><span class="p">);</span>
  <span class="k">return</span> <span class="p">(</span><span class="kt">void</span><span class="o">*</span><span class="p">)(</span><span class="n">header</span><span class="o">-&gt;</span><span class="n">data</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>We are using a simple grow strategy here: if the vector is less than 8, we grow to 8 directly, this is to reduce the number of expensive grow when vector size is small; and if the size is bigger than 8, grow 1.5x size. Note that we are using a macro <code class="language-plaintext highlighter-rouge">vheader</code> in the function to get the <code class="language-plaintext highlighter-rouge">Vec</code> structure back from the plain data, the definition is as below, which simply offset the pointer backwards to “reveal” the <strong>hidden</strong> structure.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define vheader(vector) ((Vec*)((char*)(vector) - offsetof(Vec, data)))
</span></code></pre></div></div>

<p>Since we have a function to grow our vector, we can automatically call it when user pushes a new element to the vector, we need a custom macro for it, which checks if the length overflow the capacity, grow the vector, set value, and update vector metadata.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define vadd(vector, value)                         \
  do {                                              \
    if ((vector) == NULL) {                         \
      vector = vec_new(0, 4, sizeof(*vector));      \
    }                                               \
    if (vlen(vector) + 1 &gt; vcap(vector)) {          \
      vector = vec_grow(vector);                    \
    }                                               \
    (vector)[vlen(vector)] = (value);               \
    vheader(vector)-&gt;len++;                         \
  } while (0)
</span></code></pre></div></div>

<p>In the <code class="language-plaintext highlighter-rouge">vadd</code> macro, there is a <code class="language-plaintext highlighter-rouge">if</code> branch which checks if vector is <code class="language-plaintext highlighter-rouge">NULL</code>, if it is, create a vector for the user, this is quite convenient, you don’t need to use <code class="language-plaintext highlighter-rouge">vnew</code> now, just declare the type and <code class="language-plaintext highlighter-rouge">vadd</code>, so dynamic!</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// uninitialized vector</span>
<span class="kt">float</span><span class="o">*</span> <span class="n">fvec</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="n">vadd</span><span class="p">(</span><span class="n">fvec</span><span class="p">,</span> <span class="mi">1</span><span class="p">.</span><span class="mi">0</span><span class="p">);</span>
</code></pre></div></div>

<p>There are some little helper macros here:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define vfree(vector) (free(vheader(vector)))
#define vlen(vector) (vheader(vector)-&gt;len)
#define vcap(vector) (vheader(vector)-&gt;cap)
#define vnew2(type, len, cap) vec_new(len, cap, sizeof(type))
</span></code></pre></div></div>

<p>At the end, combining all of the above, we get a easy-to-use, “generic” vector, which feels magical!</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>   <span class="c1">// new vector with len</span>
    <span class="kt">int</span><span class="o">*</span> <span class="n">vec</span> <span class="o">=</span> <span class="n">vnew</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"len = %zu, cap = %zu</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">vlen</span><span class="p">(</span><span class="n">vec</span><span class="p">),</span> <span class="n">vcap</span><span class="p">(</span><span class="n">vec</span><span class="p">));</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">vlen</span><span class="p">(</span><span class="n">vec</span><span class="p">);</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">vec</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="n">vlen</span><span class="p">(</span><span class="n">vec</span><span class="p">);</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">10</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">vadd</span><span class="p">(</span><span class="n">vec</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">vlen</span><span class="p">(</span><span class="n">vec</span><span class="p">);</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"%d "</span><span class="p">,</span> <span class="n">vec</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="p">}</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">len = %zu, cap = %zu</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">vlen</span><span class="p">(</span><span class="n">vec</span><span class="p">),</span> <span class="n">vcap</span><span class="p">(</span><span class="n">vec</span><span class="p">));</span>
    <span class="n">vfree</span><span class="p">(</span><span class="n">vec</span><span class="p">);</span>

    <span class="c1">// uninitialized vector</span>
    <span class="kt">float</span><span class="o">*</span> <span class="n">fvec</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="n">vadd</span><span class="p">(</span><span class="n">fvec</span><span class="p">,</span> <span class="mi">1</span><span class="p">.</span><span class="mi">0</span><span class="p">);</span>
    <span class="n">vadd</span><span class="p">(</span><span class="n">fvec</span><span class="p">,</span> <span class="mi">2</span><span class="p">.</span><span class="mi">0</span><span class="p">);</span>
    <span class="n">vadd</span><span class="p">(</span><span class="n">fvec</span><span class="p">,</span> <span class="mi">3</span><span class="p">.</span><span class="mi">0</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">vlen</span><span class="p">(</span><span class="n">fvec</span><span class="p">);</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"%f "</span><span class="p">,</span> <span class="n">fvec</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="p">}</span>
    <span class="n">vfree</span><span class="p">(</span><span class="n">fvec</span><span class="p">);</span>
</code></pre></div></div>]]></content><author><name></name></author><summary type="html"><![CDATA[github repo]]></summary></entry><entry><title type="html">Lambda Calculus Interpreter</title><link href="https://guiyuanju.github.io/lambda-calculus-interpreter.html" rel="alternate" type="text/html" title="Lambda Calculus Interpreter" /><published>2025-12-24T00:00:00+00:00</published><updated>2025-12-24T00:00:00+00:00</updated><id>https://guiyuanju.github.io/lambda-calculus-interpreter</id><content type="html" xml:base="https://guiyuanju.github.io/lambda-calculus-interpreter.html"><![CDATA[<p>A Lambda Calculus Interpreter written in Go compiled to WASM, see source on <a href="https://github.com/guiyuanju/lamb">Github</a>.</p>

<details>
  <summary>Click to Show Syntax</summary>
  <div>
    <p>Function/abstraction: <code class="language-plaintext highlighter-rouge">(\x.x)</code>, <code class="language-plaintext highlighter-rouge">(\x.(\y.y x))</code></p>

    <p>Application: <code class="language-plaintext highlighter-rouge">((\x.x y) y)</code> =&gt; <code class="language-plaintext highlighter-rouge">(y y)</code>.</p>

    <p>Let syntax sugar: <code class="language-plaintext highlighter-rouge">let x = y in ...</code>, replace all y with x, can be nested like <code class="language-plaintext highlighter-rouge">let a = A in let b = B in (a b)</code> =&gt; <code class="language-plaintext highlighter-rouge">(A B)</code></p>

  </div>
</details>

<details>
  <summary>Click to Show Examples</summary>
  <div>
    <p>A function that returns its argument:</p>

    <blockquote>
      <p>(\x.x) y</p>
    </blockquote>

    <p>Infinite self-application function, but interpreter detected and prevent the infinite evaluation:</p>

    <blockquote>
      <p>(\x.x x) (\x.x x)</p>
    </blockquote>

    <p>Define number zero in Church encoding and successor function, then calculate the successor of 0:</p>

    <blockquote>
      <p>let 0 = \f.\x.x in let succ = \n.\f.\x.f (n f x) in succ 0</p>
    </blockquote>

    <p>Define number from 0 to 9, + - * /, if, and, or, not, and Y combinator and then calculate 6 * 7:</p>

    <blockquote>
      <p>let succ = \n.\f.\x.f (n f x) in let pred = \n.\f.\x.n (\g.\h.h (g f)) (\u.x) (\u.u) in let 0 = \f.\x.x in let 1 = succ 0 in let 2 = succ 1 in let 3 = succ 2 in let 4 = succ 3 in let 5 = succ 4 in let 6 = succ 5 in let 7 = succ 6 in let 8 = succ 7 in let 9 = succ 8 in let + = \m.\n.\f.\x.m f (n f x) in let - = \m.\n.n pred m in let * = \m.\n.m (+ n) 0 in let pow = \b.\n.n b in let true = \x.\y.x in let false = \x.\y.y in let and = \p.\q.p q p in let or = \p.\q.p p q in let not = \p.p false true in let if = \p.\a.\b.p a b in let zero? = \n.n (\x.false) true in let &lt;= = \m.\n.zero? (- m n) in let Y = \g.(\x.g (x x)) (\x.g (x x)) in (* 6 7)</p>
    </blockquote>

  </div>
</details>

<p><br /></p>

<style>
/* Container fills available space */
.repl {
    display: flex;
    flex-direction: column;
    height: 50vh;
    width: 100%;
    background: #0f0f0f;
    color: #eaeaea;
    font-family: monospace;
    font-size: 14px;
}

/* Scrollable output area */
.repl-output {
    flex: 1;
    overflow-y: auto;
    overflow-x: auto; 
    padding: 12px;
    white-space: pre; 
    /* white-space: pre-wrap; */
}

/* Each entry */
.repl-entry {
    margin-bottom: 10px;
}

/* Input line fixed at bottom */
.repl-input-line {
    display: flex;
    padding: 10px;
    border-top: 1px solid #333;
    background: #111;
    color: black;
}

/* Prompt */
.prompt {
    margin-right: 8px;
    color: white;
}

/* Input field */
#stdin {
    flex: 1;
    background: transparent;
    border: none;
    color: inherit;
    font-family: inherit;
    font-size: inherit;
    outline: none;
}
</style>

<div class="repl">
    <div class="repl-output" id="stdout"></div>

    <div class="repl-input-line">
        <span class="prompt">λ</span>
        <input type="text" id="stdin" autofocus="" />
    </div>

</div>

<script src="/assets/js/wasm_exec.js"></script>

<script>
const go = new Go();

WebAssembly.instantiateStreaming(
    fetch("/assets/wasm/la.wasm"),
    go.importObject
).then((result) => {
    go.run(result.instance);
});

const stdin = document.getElementById("stdin");
const stdout = document.getElementById("stdout");

/* Scroll to bottom */
function scrollToBottom() {
    stdout.scrollTop = stdout.scrollHeight;
}

/* Append a REPL entry */
function appendEntry(input, result) {
    const entry = document.createElement("div");
    entry.className = "repl-entry";

    const line = document.createElement("div");
    line.innerHTML = `<span class="prompt">λ</span>${input}`;

    const output = document.createElement("div");
    output.textContent = result.replace(/\n+$/, ""); // trim trailing newlines

    entry.appendChild(line);
    entry.appendChild(output);

    stdout.appendChild(entry);
}

/* Handle input */
stdin.addEventListener("keydown", function (e) {
    if (e.key === "Enter") {
        e.preventDefault();

        const input = stdin.value;
        if (!input) return;

        let result;
        try {
            result = run(input);
        } catch (err) {
            result = String(err);
        }

        appendEntry(input, result);

        stdin.value = "";
        scrollToBottom();
    }
});

/* Keep focus on input */
// document.addEventListener("click", () => {
//     stdin.focus();
// });
</script>]]></content><author><name></name></author><summary type="html"><![CDATA[A Lambda Calculus Interpreter written in Go compiled to WASM, see source on Github.]]></summary></entry><entry><title type="html">HashTable from Scratch and Benchmarking</title><link href="https://guiyuanju.github.io/implementing-a-hashtable-in-rust.html" rel="alternate" type="text/html" title="HashTable from Scratch and Benchmarking" /><published>2025-08-18T00:00:00+00:00</published><updated>2025-08-18T00:00:00+00:00</updated><id>https://guiyuanju.github.io/Implementing-a-HashTable-in-Rust</id><content type="html" xml:base="https://guiyuanju.github.io/implementing-a-hashtable-in-rust.html"><![CDATA[<p><a href="https://github.com/guiyuanju/hash_table_in_rust">Link for Code</a></p>

<p>Recently, I wanted to revisit Rust, and while following along with the book <em>Crafting Interpreters</em>, I came across the chapter on implementing a Hash Table. I discovered many interesting details about Hash Table implementations, which inspired me to write this blog post. I will implement a Hash Table using Rust and conduct some possibly non-standard benchmarks.</p>

<p>A Hash Table typically consists of two main components:</p>

<ol>
  <li>A hash function</li>
  <li>A collision resolution strategy, commonly including:
a. Chaining
b. Linear probing</li>
</ol>

<p>In our Hash Table, we will use ⁠String as the key type and a simple hash function called FNV-1a to compute the hash value. To avoid recalculating the hash value on each query, we will precompute and cache it within the key.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">struct</span> <span class="n">KeyValue</span> <span class="p">{</span>
    <span class="n">key</span><span class="p">:</span> <span class="n">Key</span><span class="p">,</span>
    <span class="n">value</span><span class="p">:</span> <span class="n">Value</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">Key</span> <span class="p">{</span>
    <span class="n">name</span><span class="p">:</span> <span class="nb">String</span><span class="p">,</span>
    <span class="n">hash</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Key</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="o">&amp;</span><span class="nb">str</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
        <span class="k">let</span> <span class="k">mut</span> <span class="n">hash</span><span class="p">:</span> <span class="nb">u32</span> <span class="o">=</span> <span class="mi">2166136261u32</span><span class="p">;</span>
        <span class="k">for</span> <span class="o">&amp;</span><span class="n">b</span> <span class="k">in</span> <span class="n">name</span><span class="nf">.as_bytes</span><span class="p">()</span> <span class="p">{</span>
            <span class="n">hash</span> <span class="o">^=</span> <span class="n">b</span> <span class="k">as</span> <span class="nb">u32</span><span class="p">;</span>
            <span class="n">hash</span> <span class="o">=</span> <span class="n">hash</span><span class="nf">.wrapping_mul</span><span class="p">(</span><span class="mi">16777619</span><span class="p">);</span>
        <span class="p">}</span>

        <span class="k">Self</span> <span class="p">{</span>
            <span class="n">name</span><span class="p">:</span> <span class="n">name</span><span class="nf">.to_string</span><span class="p">(),</span>
            <span class="n">hash</span><span class="p">,</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">enum</span> <span class="n">Value</span> <span class="p">{</span>
    <span class="nf">Boolean</span><span class="p">(</span><span class="nb">bool</span><span class="p">),</span>
    <span class="nf">Number</span><span class="p">(</span><span class="nb">f64</span><span class="p">),</span>
    <span class="nf">String</span><span class="p">(</span><span class="nb">String</span><span class="p">),</span>
<span class="p">}</span>
</code></pre></div></div>

<p>A Hash Table requires an array as storage space, and it must also keep track of how many entries are currently stored in the array to facilitate space expansion when it approaches capacity.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">struct</span> <span class="n">Table</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="n">count</span><span class="p">:</span> <span class="nb">usize</span><span class="p">,</span>
    <span class="n">entries</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">Entry</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">enum</span> <span class="n">Entry</span> <span class="p">{</span>
    <span class="nf">KeyValue</span><span class="p">(</span><span class="n">KeyValue</span><span class="p">),</span>
    <span class="n">Tombstone</span><span class="p">,</span>
    <span class="nb">None</span><span class="p">,</span>
<span class="p">}</span>
</code></pre></div></div>

<p>⁠The ⁠entries array is where the actual data is stored, and each element is an ⁠enum with three possible states: the first indicates data is present, the second indicates the data has been deleted, and the third indicates no data exists. A ⁠Tombstone is a common technique used to implement the delete operation in a Hash Table. If the Hash Table uses chaining to resolve collisions, the delete operation is straightforward; you simply remove the corresponding element from the chain. However, to reduce the probability of CPU cache misses, we will use linear probing for our implementation.</p>

<p>Unlike chaining, when a collision occurs, linear probing searches the array to find the first available space to store the element. During lookups, if the target key is not found at the desired index, it continues to search sequentially until it encounters an empty element or finds the target key.</p>

<p>However, the delete operation in linear probing is relatively challenging to implement. Imagine if we simply remove an element, it introduces an empty slot, which could break the “chain” of other key lookups. A tombstone provides a solution by replacing the element to be deleted with a tombstone. When a lookup encounters a tombstone, it continues searching, thus preserving the “chain.” When inserting, if a tombstone is encountered, it is simply replaced, avoiding wasting space.</p>

<p>Before implementing insert, lookup, and delete operations, we define a helper function, ⁠find_entry, which is responsible for searching for a specified key. If found, it returns the corresponding index; if not found, it returns an index where the key can be inserted. This insertable index may correspond to either an empty element or a tombstone.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">enum</span> <span class="n">FindResult</span> <span class="p">{</span>
    <span class="nf">Found</span><span class="p">(</span><span class="nb">usize</span><span class="p">),</span>
    <span class="nf">Available</span><span class="p">(</span><span class="nb">usize</span><span class="p">),</span>
    <span class="nf">Tombstone</span><span class="p">(</span><span class="nb">usize</span><span class="p">),</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">find_entry</span><span class="p">(</span><span class="n">entries</span><span class="p">:</span> <span class="o">&amp;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="n">Entry</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">Key</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">FindResult</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">index</span> <span class="o">=</span> <span class="p">(</span><span class="n">key</span><span class="py">.hash</span> <span class="o">%</span> <span class="n">entries</span><span class="nf">.len</span><span class="p">()</span> <span class="k">as</span> <span class="nb">u32</span><span class="p">)</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">;</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">tombstone</span><span class="p">:</span> <span class="nb">Option</span><span class="o">&lt;</span><span class="n">FindResult</span><span class="o">&gt;</span> <span class="o">=</span> <span class="nb">None</span><span class="p">;</span>

    <span class="k">loop</span> <span class="p">{</span>
        <span class="k">match</span> <span class="o">&amp;</span><span class="n">entries</span><span class="p">[</span><span class="n">index</span><span class="p">]</span> <span class="p">{</span>
            <span class="nn">Entry</span><span class="p">::</span><span class="nf">KeyValue</span><span class="p">(</span><span class="n">kv</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="p">{</span>
                <span class="k">if</span> <span class="n">kv</span><span class="py">.key</span> <span class="o">==</span> <span class="o">*</span><span class="n">key</span> <span class="p">{</span>
                    <span class="k">return</span> <span class="nn">FindResult</span><span class="p">::</span><span class="nf">Found</span><span class="p">(</span><span class="n">index</span><span class="p">);</span>
                <span class="p">}</span>
            <span class="p">}</span>
            <span class="nn">Entry</span><span class="p">::</span><span class="n">Tombstone</span> <span class="k">=&gt;</span> <span class="p">{</span>
                <span class="k">if</span> <span class="n">tombstone</span><span class="nf">.is_none</span><span class="p">()</span> <span class="p">{</span>
                    <span class="n">tombstone</span> <span class="o">=</span> <span class="nf">Some</span><span class="p">(</span><span class="nn">FindResult</span><span class="p">::</span><span class="nf">Tombstone</span><span class="p">(</span><span class="n">index</span><span class="p">))</span>
                <span class="p">}</span>
            <span class="p">}</span>
            <span class="nn">Entry</span><span class="p">::</span><span class="nb">None</span> <span class="k">=&gt;</span> <span class="p">{</span>
                <span class="k">if</span> <span class="n">tombstone</span><span class="nf">.is_some</span><span class="p">()</span> <span class="p">{</span>
                    <span class="k">return</span> <span class="n">tombstone</span><span class="nf">.unwrap</span><span class="p">();</span>
                <span class="p">}</span>
                <span class="k">return</span> <span class="nn">FindResult</span><span class="p">::</span><span class="nf">Available</span><span class="p">(</span><span class="n">index</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">}</span>

        <span class="n">index</span> <span class="o">=</span> <span class="p">(</span><span class="n">index</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="n">entries</span><span class="nf">.len</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Next, we will implement the lookup operation ⁠get. Since we already have ⁠find_entry, implementing the lookup becomes very straightforward.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span> <span class="n">Table</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">get</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">Key</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Option</span><span class="o">&lt;</span><span class="n">Value</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.entries</span><span class="nf">.len</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">return</span> <span class="nb">None</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">if</span> <span class="k">let</span> <span class="nn">FindResult</span><span class="p">::</span><span class="nf">Found</span><span class="p">(</span><span class="n">entry_index</span><span class="p">)</span> <span class="o">=</span> <span class="nf">find_entry</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="py">.entries</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">key</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="k">let</span> <span class="nn">Entry</span><span class="p">::</span><span class="nf">KeyValue</span><span class="p">(</span><span class="n">kv</span><span class="p">)</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">self</span><span class="py">.entries</span><span class="p">[</span><span class="n">entry_index</span><span class="p">]</span> <span class="p">{</span>
                <span class="k">return</span> <span class="nf">Some</span><span class="p">(</span><span class="n">kv</span><span class="py">.value</span><span class="nf">.clone</span><span class="p">());</span>
            <span class="p">}</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="nb">None</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The insert operation ⁠set is a bit more complex than lookup because there might be insufficient space in the array during insertion. To optimize performance, we cannot wait until the space is nearly full to expand it. As the available space decreases, the probability of collisions increases, leading to longer lookup times. Therefore, we define a ⁠MAX_LOAD threshold, indicating when the used space reaches a certain ratio, prompting space expansion.</p>

<p>Here, we define another helper function, ⁠adjust_capacity, to handle space expansion. Inside this function, we first allocate a larger space and then traverse the original space, inserting existing elements one by one.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span> <span class="n">Table</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">adjust_capacity</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">capacity</span><span class="p">:</span> <span class="nb">usize</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="k">mut</span> <span class="n">entries</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">Entry</span><span class="o">&gt;</span> <span class="o">=</span> <span class="nd">vec!</span><span class="p">[</span><span class="nn">Entry</span><span class="p">::</span><span class="nb">None</span><span class="p">;</span> <span class="n">capacity</span><span class="p">];</span>

        <span class="k">self</span><span class="py">.count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="k">for</span> <span class="n">e</span> <span class="k">in</span> <span class="o">&amp;</span><span class="k">self</span><span class="py">.entries</span> <span class="p">{</span>
            <span class="k">if</span> <span class="k">let</span> <span class="nn">Entry</span><span class="p">::</span><span class="nf">KeyValue</span><span class="p">(</span><span class="n">entry</span><span class="p">)</span> <span class="o">=</span> <span class="n">e</span> <span class="p">{</span>
                <span class="k">if</span> <span class="k">let</span> <span class="nn">FindResult</span><span class="p">::</span><span class="nf">Available</span><span class="p">(</span><span class="n">index</span><span class="p">)</span> <span class="o">=</span> <span class="nf">find_entry</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">entries</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">entry</span><span class="py">.key</span><span class="p">)</span> <span class="p">{</span>
                    <span class="n">entries</span><span class="p">[</span><span class="n">index</span><span class="p">]</span> <span class="o">=</span> <span class="nn">Entry</span><span class="p">::</span><span class="nf">KeyValue</span><span class="p">(</span><span class="n">entry</span><span class="nf">.clone</span><span class="p">());</span>
                    <span class="k">self</span><span class="py">.count</span> <span class="o">+=</span> <span class="mi">1</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>

        <span class="k">self</span><span class="py">.entries</span> <span class="o">=</span> <span class="n">entries</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>With ⁠adjust_capacity implemented, we can now implement the ⁠set operation. First, we check whether inserting will exceed the load threshold. If it does, we expand the space (I arbitrarily chose a strategy: if the length is less than 8, expand it to 8 directly; otherwise, double the current length). Then, we use ⁠find_entry to determine the index where we can insert the key. If ⁠Found is returned, it means the key already exists, so we update it; if ⁠Available is returned, it means the key does not exist, and there is an empty slot available, so we increment the element count ⁠count and insert the new entry; if ⁠Tombstone is returned, we treat the tombstone as an existing element and do not increment ⁠count. This is crucial because if we do not consider the tombstone as an existing element, when the array is filled with tombstones and no empty slots remain, ⁠find_entry could enter an infinite loop.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span> <span class="n">Table</span> <span class="p">{</span>
    <span class="k">const</span> <span class="n">MAX_LOAD</span><span class="p">:</span> <span class="nb">f32</span> <span class="o">=</span> <span class="mf">0.75</span><span class="p">;</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">set</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">Key</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">Value</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="k">self</span><span class="py">.count</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="k">as</span> <span class="nb">f32</span> <span class="o">&gt;</span> <span class="k">Self</span><span class="p">::</span><span class="n">MAX_LOAD</span> <span class="o">*</span> <span class="k">self</span><span class="py">.entries</span><span class="nf">.len</span><span class="p">()</span> <span class="k">as</span> <span class="nb">f32</span> <span class="p">{</span>
            <span class="k">let</span> <span class="n">capacity</span> <span class="o">=</span> <span class="k">if</span> <span class="k">self</span><span class="py">.entries</span><span class="nf">.len</span><span class="p">()</span> <span class="o">&lt;</span> <span class="mi">8</span> <span class="p">{</span>
                <span class="mi">8</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="k">self</span><span class="py">.entries</span><span class="nf">.len</span><span class="p">()</span> <span class="o">*</span> <span class="mi">2</span>
            <span class="p">};</span>

            <span class="k">self</span><span class="nf">.adjust_capacity</span><span class="p">(</span><span class="n">capacity</span><span class="p">);</span>
        <span class="p">}</span>

        <span class="k">let</span> <span class="n">index</span> <span class="o">=</span> <span class="k">match</span> <span class="nf">find_entry</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="py">.entries</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">key</span><span class="p">)</span> <span class="p">{</span>
            <span class="nn">FindResult</span><span class="p">::</span><span class="nf">Found</span><span class="p">(</span><span class="n">index</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">index</span><span class="p">,</span>
            <span class="nn">FindResult</span><span class="p">::</span><span class="nf">Available</span><span class="p">(</span><span class="n">index</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="p">{</span>
                <span class="k">self</span><span class="py">.count</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span>
                <span class="n">index</span>
            <span class="p">}</span>
            <span class="nn">FindResult</span><span class="p">::</span><span class="nf">Tombstone</span><span class="p">(</span><span class="n">index</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">index</span><span class="p">,</span>
        <span class="p">};</span>
        <span class="k">self</span><span class="py">.entries</span><span class="p">[</span><span class="n">index</span><span class="p">]</span> <span class="o">=</span> <span class="nn">Entry</span><span class="p">::</span><span class="nf">KeyValue</span><span class="p">(</span><span class="n">KeyValue</span> <span class="p">{</span>
            <span class="n">key</span><span class="p">:</span> <span class="n">key</span><span class="nf">.clone</span><span class="p">(),</span>
            <span class="n">value</span><span class="p">:</span> <span class="n">value</span><span class="nf">.clone</span><span class="p">(),</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>With the tombstone mechanism in place, implementing the delete operation becomes quite simple; we just replace the corresponding element with a tombstone.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span> <span class="n">Table</span> <span class="p">{</span>
	<span class="k">pub</span> <span class="k">fn</span> <span class="nf">delete</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">Key</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.count</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">return</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">if</span> <span class="k">let</span> <span class="nn">FindResult</span><span class="p">::</span><span class="nf">Found</span><span class="p">(</span><span class="n">index</span><span class="p">)</span> <span class="o">=</span> <span class="nf">find_entry</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="py">.entries</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">key</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.entries</span><span class="p">[</span><span class="n">index</span><span class="p">]</span> <span class="o">=</span> <span class="nn">Entry</span><span class="p">::</span><span class="n">Tombstone</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Now, we have a complete and functional Hash Table implementation. Let’s perform some benchmarks.</p>

<p>I define an operation that involves inserting a certain number <code class="language-plaintext highlighter-rouge">⁠n</code> of elements, then deleting <code class="language-plaintext highlighter-rouge">⁠n/10</code> of those elements, and finally querying ⁠<code class="language-plaintext highlighter-rouge">n*200</code> times to calculate the average time taken for each operation.</p>

<p>The results are as follows, where the x-axis represents the number of elements ⁠n (from 10 to 1500), and the y-axis represents the average time taken for operations at the current scale. It can be observed that the average time fluctuates in a sawtooth pattern as the scale increases. Each rising segment indicates that, under fixed storage size, the operation times increase as the number of elements stored in the Hash Table increases (indicating more collisions). When the threshold is reached, the space is expanded, and the average operation time drops accordingly.</p>

<p><img src="/assets/images/244E2B0BC39A82FB57745536193C9312.png" alt="average op time" /></p>

<p>Additionally, I calculated the amortized operation time. Similarly, the x-axis represents the input size, but the y-axis shows the average time taken for all operations up to that point. It can be seen that the amortized time complexity of the Hash Table indeed approaches O(1).</p>

<p><img src="/assets/images/8AF2B7052E9543A14EF8DB5B4DBAC41F.png" alt="amortized op time" /></p>

<p>Through this implementation, I gained insights into some unique details of Hash Tables, such as the peculiarities of deletion in linear probing, the pros and cons of different collision resolution algorithms, and the actual time complexity of Hash Tables.</p>

<p>There are many more aspects to discuss regarding Hash Tables, such as comparing the performance of different hash functions, empirically comparing the performance differences of various collision solving algorithms, and exploring algorithmic performance beyond the tombstone mechanism in linear probing. These topics are left for future exploration.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Link for Code]]></summary></entry><entry><title type="html">Improve Performance Greatly By Eliminating Branches</title><link href="https://guiyuanju.github.io/leetcode-496-next-greater-element-i.html" rel="alternate" type="text/html" title="Improve Performance Greatly By Eliminating Branches" /><published>2025-05-20T00:00:00+00:00</published><updated>2025-05-20T00:00:00+00:00</updated><id>https://guiyuanju.github.io/Leetcode-496-Next-Greater-Element-I</id><content type="html" xml:base="https://guiyuanju.github.io/leetcode-496-next-greater-element-i.html"><![CDATA[<h2 id="problem">Problem</h2>

<p>The next greater element of some element <code class="language-plaintext highlighter-rouge">x</code> in an array is the first greater element that is to the right of <code class="language-plaintext highlighter-rouge">x</code> in the same array.</p>

<p>You are given two distinct 0-indexed integer arrays <code class="language-plaintext highlighter-rouge">nums1</code> and <code class="language-plaintext highlighter-rouge">nums2</code>, where <code class="language-plaintext highlighter-rouge">nums1</code> is a subset of <code class="language-plaintext highlighter-rouge">nums2</code>.</p>

<p>For each <code class="language-plaintext highlighter-rouge">0 &lt;= i &lt; nums1.length</code>, find the index <code class="language-plaintext highlighter-rouge">j</code> such that <code class="language-plaintext highlighter-rouge">nums1[i] == nums2[j]</code> and determine the next greater element of <code class="language-plaintext highlighter-rouge">nums2[j]</code> in <code class="language-plaintext highlighter-rouge">nums2</code>. If there is no next greater element, then the answer for this query is -1.</p>

<p>Return an array ans of length <code class="language-plaintext highlighter-rouge">nums1.length</code> such that <code class="language-plaintext highlighter-rouge">ans[i]</code> is the next greater element as described above.</p>

<p><strong>Example 1:</strong></p>

<blockquote>
  <p>Input: <code class="language-plaintext highlighter-rouge">nums1 = [4,1,2]</code>, <code class="language-plaintext highlighter-rouge">nums2 = [1,3,4,2]</code>
Output: <code class="language-plaintext highlighter-rouge">[-1,3,-1]</code>
Explanation: The next greater element for each value of nums1 is as follows:</p>

  <ul>
    <li>4 is underlined in <code class="language-plaintext highlighter-rouge">nums2 = [1,3,4,2]</code>. There is no next greater element, so the answer is -1.</li>
    <li>1 is underlined in <code class="language-plaintext highlighter-rouge">nums2 = [1,3,4,2]</code>. The next greater element is 3.</li>
    <li>2 is underlined in <code class="language-plaintext highlighter-rouge">nums2 = [1,3,4,2]</code>. There is no next greater element, so the answer is -1.</li>
  </ul>
</blockquote>

<p><strong>Example 2:</strong></p>

<blockquote>
  <p>Input: <code class="language-plaintext highlighter-rouge">nums1 = [2,4]</code>, <code class="language-plaintext highlighter-rouge">nums2 = [1,2,3,4]</code>
Output: <code class="language-plaintext highlighter-rouge">[3,-1]</code>
Explanation: The next greater element for each value of nums1 is as follows:</p>

  <ul>
    <li>2 is underlined in <code class="language-plaintext highlighter-rouge">nums2 = [1,2,3,4]</code>. The next greater element is 3.</li>
    <li>4 is underlined in <code class="language-plaintext highlighter-rouge">nums2 = [1,2,3,4]</code>. There is no next greater element, so the answer is -1.</li>
  </ul>
</blockquote>

<p>Constraints:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">1 &lt;= nums1.length &lt;= nums2.length &lt;= 1000</code></li>
  <li><code class="language-plaintext highlighter-rouge">0 &lt;= nums1[i]</code>, <code class="language-plaintext highlighter-rouge">nums2[i] &lt;= 104</code></li>
  <li>All integers in <code class="language-plaintext highlighter-rouge">nums1</code> and <code class="language-plaintext highlighter-rouge">nums2</code> are unique.</li>
  <li>All the integers of <code class="language-plaintext highlighter-rouge">nums1</code> also appear in <code class="language-plaintext highlighter-rouge">nums2</code>.</li>
</ul>

<h2 id="solution">Solution</h2>

<p>With the <em>monotonic stack</em> technique, we could achieve O(n) time complexity.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">nextGreaterElement</span><span class="p">(</span><span class="n">nums1</span> <span class="p">[]</span><span class="kt">int</span><span class="p">,</span> <span class="n">nums2</span> <span class="p">[]</span><span class="kt">int</span><span class="p">)</span> <span class="p">[]</span><span class="kt">int</span> <span class="p">{</span>
	<span class="n">greater</span> <span class="o">:=</span> <span class="k">map</span><span class="p">[</span><span class="kt">int</span><span class="p">]</span><span class="kt">int</span><span class="p">{}</span>
	<span class="n">decreasing</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">int</span><span class="p">{}</span>
	<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">n</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">nums2</span> <span class="p">{</span>
		<span class="k">for</span> <span class="nb">len</span><span class="p">(</span><span class="n">decreasing</span><span class="p">)</span> <span class="o">&gt;</span> <span class="m">0</span> <span class="o">&amp;&amp;</span> <span class="n">n</span> <span class="o">&gt;</span> <span class="n">decreasing</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="n">decreasing</span><span class="p">)</span><span class="o">-</span><span class="m">1</span><span class="p">]</span> <span class="p">{</span>
			<span class="n">greater</span><span class="p">[</span><span class="n">decreasing</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="n">decreasing</span><span class="p">)</span><span class="o">-</span><span class="m">1</span><span class="p">]]</span> <span class="o">=</span> <span class="n">n</span>
			<span class="n">decreasing</span> <span class="o">=</span> <span class="n">decreasing</span><span class="p">[</span><span class="o">:</span><span class="nb">len</span><span class="p">(</span><span class="n">decreasing</span><span class="p">)</span><span class="o">-</span><span class="m">1</span><span class="p">]</span>
		<span class="p">}</span>
		<span class="n">decreasing</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">decreasing</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span>
	<span class="p">}</span>

	<span class="k">var</span> <span class="n">res</span> <span class="p">[]</span><span class="kt">int</span>
	<span class="c">// !!!!!!!!!!!</span>
	<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">n</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">nums1</span> <span class="p">{</span>
		<span class="k">if</span> <span class="n">v</span><span class="p">,</span> <span class="n">ok</span> <span class="o">:=</span> <span class="n">greater</span><span class="p">[</span><span class="n">n</span><span class="p">];</span> <span class="n">ok</span> <span class="p">{</span>
			<span class="n">res</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
		<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
			<span class="n">res</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="o">-</span><span class="m">1</span><span class="p">)</span>
		<span class="p">}</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="n">res</span>
<span class="p">}</span>
</code></pre></div></div>

<p>But the data shows it only beats <strong>17%</strong> solutions in terms of runtime.</p>

<p>What happened?</p>

<p>Notice the <code class="language-plaintext highlighter-rouge">!!!!!!!!!!!</code> comment line in the solution, the code under it is very suspicious, as we all (maybe) know,
<code class="language-plaintext highlighter-rouge">if</code> statement inside a loop causes performance penalties, because of the <em>branch prediction failure</em>,
okay, let’s eliminate the branch: instead of determin whether the number exists in the map, we loop over the stack,
and assign <code class="language-plaintext highlighter-rouge">-1</code> to the corresponding element in the map <strong>in advance</strong>.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">nextGreaterElement</span><span class="p">(</span><span class="n">nums1</span> <span class="p">[]</span><span class="kt">int</span><span class="p">,</span> <span class="n">nums2</span> <span class="p">[]</span><span class="kt">int</span><span class="p">)</span> <span class="p">[]</span><span class="kt">int</span> <span class="p">{</span>
	<span class="n">greater</span> <span class="o">:=</span> <span class="k">map</span><span class="p">[</span><span class="kt">int</span><span class="p">]</span><span class="kt">int</span><span class="p">{}</span>
	<span class="n">decreasing</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">int</span><span class="p">{}</span>
	<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">n</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">nums2</span> <span class="p">{</span>
		<span class="k">for</span> <span class="nb">len</span><span class="p">(</span><span class="n">decreasing</span><span class="p">)</span> <span class="o">&gt;</span> <span class="m">0</span> <span class="o">&amp;&amp;</span> <span class="n">n</span> <span class="o">&gt;</span> <span class="n">decreasing</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="n">decreasing</span><span class="p">)</span><span class="o">-</span><span class="m">1</span><span class="p">]</span> <span class="p">{</span>
			<span class="n">greater</span><span class="p">[</span><span class="n">decreasing</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="n">decreasing</span><span class="p">)</span><span class="o">-</span><span class="m">1</span><span class="p">]]</span> <span class="o">=</span> <span class="n">n</span>
			<span class="n">decreasing</span> <span class="o">=</span> <span class="n">decreasing</span><span class="p">[</span><span class="o">:</span><span class="nb">len</span><span class="p">(</span><span class="n">decreasing</span><span class="p">)</span><span class="o">-</span><span class="m">1</span><span class="p">]</span>
		<span class="p">}</span>
		<span class="n">decreasing</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">decreasing</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span>
	<span class="p">}</span>

	<span class="c">// added here</span>
	<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">n</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">decreasing</span> <span class="p">{</span>
		<span class="n">greater</span><span class="p">[</span><span class="n">n</span><span class="p">]</span> <span class="o">=</span> <span class="o">-</span><span class="m">1</span>
	<span class="p">}</span>

	<span class="k">var</span> <span class="n">res</span> <span class="p">[]</span><span class="kt">int</span>
	<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">n</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">nums1</span> <span class="p">{</span>
		<span class="n">res</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">greater</span><span class="p">[</span><span class="n">n</span><span class="p">])</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="n">res</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Submit it again, and boom! <strong>100%</strong> beats!</p>

<p>Algorithms aren’t the only core of performance, but also subtle places like this, which directly related to the
structure of modern CPU.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Problem]]></summary></entry><entry><title type="html">Book Reading: Crafting Interpreters</title><link href="https://guiyuanju.github.io/crafting-interpreters.html" rel="alternate" type="text/html" title="Book Reading: Crafting Interpreters" /><published>2025-04-29T00:00:00+00:00</published><updated>2025-04-29T00:00:00+00:00</updated><id>https://guiyuanju.github.io/Crafting-Interpreters</id><content type="html" xml:base="https://guiyuanju.github.io/crafting-interpreters.html"><![CDATA[<p>I’ve been reading <a href="https://craftinginterpreters.com">Crafting Interpreters</a> on and off for a long time, and I finally finished it tonight—what a wonderful journey! I highly recommend it to anyone interested in learning how interpreters and compilers are implemented.</p>

<p>The book walks you through building a tree-walk interpreter (in Java) and a single-pass compiler that generates bytecode for a stack-based virtual machine (in C)—all coded by hand!</p>

<p>It took me over 40 hours (and a bit of pain) to complete the book, especially during the compiler implementation. So take your time and be patient—it’s worth it.</p>

<ul>
  <li><a href="https://github.com/guiyuanju/jlox">Lox implementation in Java</a></li>
  <li><a href="https://github.com/guiyuanju/clox">Lox implementation in C</a></li>
</ul>]]></content><author><name></name></author><summary type="html"><![CDATA[I’ve been reading Crafting Interpreters on and off for a long time, and I finally finished it tonight—what a wonderful journey! I highly recommend it to anyone interested in learning how interpreters and compilers are implemented.]]></summary></entry><entry><title type="html">SwiftUI Ignores Unused State Variables</title><link href="https://guiyuanju.github.io/swiftui-changes-to-unused-state-variables-in-the-body-may-be-ignored.html" rel="alternate" type="text/html" title="SwiftUI Ignores Unused State Variables" /><published>2025-03-28T00:00:00+00:00</published><updated>2025-03-28T00:00:00+00:00</updated><id>https://guiyuanju.github.io/SwiftUI-Changes-to-Unused-State-Variables-in-the-Body-May-Be-Ignored</id><content type="html" xml:base="https://guiyuanju.github.io/swiftui-changes-to-unused-state-variables-in-the-body-may-be-ignored.html"><![CDATA[<p>This issue arose from a project I was working on for the “100 Days of SwiftUI” challenge. The application allows users to select a photo from their library and assign a name to it. While it’s a simple app, it presented a puzzling challenge.</p>

<p>Below is the initial version of the code I attempted. It failed at an unexpected point—can you identify the issue?</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">import</span> <span class="kt">SwiftUI</span>
<span class="kd">import</span> <span class="kt">PhotosUI</span>

<span class="kd">struct</span> <span class="kt">ContentView</span><span class="p">:</span> <span class="kt">View</span> <span class="p">{</span>
    <span class="kd">@State</span> <span class="kd">private</span> <span class="k">var</span> <span class="nv">namedPhotos</span><span class="p">:</span> <span class="p">[</span><span class="kt">NamedPhoto</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="kd">@State</span> <span class="kd">private</span> <span class="k">var</span> <span class="nv">pickerItem</span><span class="p">:</span> <span class="kt">PhotosPickerItem</span><span class="p">?</span>
    <span class="kd">@State</span> <span class="kd">private</span> <span class="k">var</span> <span class="nv">currentNamedPhoto</span><span class="p">:</span> <span class="kt">NamedPhoto</span><span class="p">?</span> <span class="o">=</span> <span class="kc">nil</span>
    <span class="kd">@State</span> <span class="kd">private</span> <span class="k">var</span> <span class="nv">isAskNamePresented</span> <span class="o">=</span> <span class="kc">false</span>

    <span class="k">var</span> <span class="nv">body</span><span class="p">:</span> <span class="kd">some</span> <span class="kt">View</span> <span class="p">{</span>
        <span class="kt">PhotosPicker</span><span class="p">(</span><span class="s">"Select a photo"</span><span class="p">,</span> <span class="nv">selection</span><span class="p">:</span> <span class="err">$</span><span class="n">pickerItem</span><span class="p">,</span> <span class="nv">matching</span><span class="p">:</span> <span class="o">.</span><span class="n">images</span><span class="p">)</span>
            <span class="o">.</span><span class="nf">onChange</span><span class="p">(</span><span class="nv">of</span><span class="p">:</span> <span class="n">pickerItem</span><span class="p">)</span> <span class="p">{</span><span class="n">_</span><span class="p">,</span> <span class="n">newItem</span> <span class="k">in</span>
                <span class="kt">Task</span> <span class="p">{</span>
                    <span class="k">if</span> <span class="k">let</span> <span class="nv">data</span> <span class="o">=</span> <span class="k">try</span> <span class="k">await</span> <span class="n">newItem</span><span class="p">?</span><span class="o">.</span><span class="nf">loadTransferable</span><span class="p">(</span><span class="nv">type</span><span class="p">:</span> <span class="kt">Data</span><span class="o">.</span><span class="k">self</span><span class="p">)</span> <span class="p">{</span>
                        <span class="n">currentNamedPhoto</span> <span class="o">=</span> <span class="kt">NamedPhoto</span><span class="p">(</span><span class="nv">photo</span><span class="p">:</span> <span class="n">data</span><span class="p">,</span> <span class="nv">name</span><span class="p">:</span> <span class="s">""</span><span class="p">)</span>
                        <span class="n">isAskNamePresented</span> <span class="o">=</span> <span class="kc">true</span>
                    <span class="p">}</span>
                <span class="p">}</span>
            <span class="p">}</span>
            <span class="o">.</span><span class="nf">sheet</span><span class="p">(</span><span class="nv">isPresented</span><span class="p">:</span> <span class="err">$</span><span class="n">isAskNamePresented</span><span class="p">)</span> <span class="p">{</span>
                <span class="kt">VStack</span> <span class="p">{</span>
                    <span class="k">if</span> <span class="k">let</span> <span class="nv">currentNamedPhoto</span> <span class="o">=</span> <span class="n">currentNamedPhoto</span> <span class="p">{</span>
                        <span class="nf">toImage</span><span class="p">(</span><span class="nv">from</span><span class="p">:</span> <span class="n">currentNamedPhoto</span><span class="o">.</span><span class="n">photo</span><span class="p">)</span>
                            <span class="o">.</span><span class="nf">resizable</span><span class="p">()</span>
                            <span class="o">.</span><span class="nf">scaledToFit</span><span class="p">()</span>
                            <span class="o">.</span><span class="nf">frame</span><span class="p">(</span><span class="nv">height</span><span class="p">:</span> <span class="mi">300</span><span class="p">)</span>
                        <span class="k">if</span> <span class="k">let</span> <span class="nv">namedPhoto</span> <span class="o">=</span> <span class="kt">Binding</span><span class="p">(</span><span class="err">$</span><span class="n">currentNamedPhoto</span><span class="p">)</span> <span class="p">{</span>
                            <span class="kt">TextField</span><span class="p">(</span><span class="s">"Name"</span><span class="p">,</span> <span class="nv">text</span><span class="p">:</span> <span class="n">namedPhoto</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
                        <span class="p">}</span>
                        <span class="kt">Button</span><span class="p">(</span><span class="s">"Add"</span><span class="p">)</span> <span class="p">{</span>
                            <span class="n">namedPhotos</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="n">currentNamedPhoto</span><span class="p">)</span>
                            <span class="n">isAskNamePresented</span> <span class="o">=</span> <span class="kc">false</span>
                        <span class="p">}</span>
                    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                        <span class="kt">Text</span><span class="p">(</span><span class="s">"No photo selected"</span><span class="p">)</span>
                    <span class="p">}</span>
                <span class="p">}</span>
            <span class="p">}</span>

        <span class="kt">List</span><span class="p">(</span><span class="n">namedPhotos</span><span class="p">,</span> <span class="nv">id</span><span class="p">:</span> <span class="p">\</span><span class="o">.</span><span class="n">id</span><span class="p">)</span> <span class="p">{</span> <span class="n">photo</span> <span class="k">in</span>
            <span class="kt">VStack</span><span class="p">(</span><span class="nv">alignment</span><span class="p">:</span> <span class="o">.</span><span class="n">leading</span><span class="p">)</span> <span class="p">{</span>
                <span class="kt">Text</span><span class="p">(</span><span class="s">"hi"</span><span class="p">)</span>
                <span class="nf">toImage</span><span class="p">(</span><span class="nv">from</span><span class="p">:</span> <span class="n">photo</span><span class="o">.</span><span class="n">photo</span><span class="p">)</span>
                    <span class="o">.</span><span class="nf">resizable</span><span class="p">()</span>
                    <span class="o">.</span><span class="nf">scaledToFit</span><span class="p">()</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="kd">func</span> <span class="nf">toImage</span><span class="p">(</span><span class="n">from</span> <span class="nv">data</span><span class="p">:</span> <span class="kt">Data</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">Image</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">let</span> <span class="nv">uiImage</span> <span class="o">=</span> <span class="kt">UIImage</span><span class="p">(</span><span class="nv">data</span><span class="p">:</span> <span class="n">data</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="kt">Image</span><span class="p">(</span><span class="nv">uiImage</span><span class="p">:</span> <span class="n">uiImage</span><span class="p">)</span>
        <span class="p">}</span>
        <span class="nf">fatalError</span><span class="p">(</span><span class="s">"Couldn't convert data to UIImage"</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>To briefly explain the code: the ⁠PhotosPicker allows users to select a photo from their library. Once the photo data is loaded, the sheet is triggered by updating the variable. This is the key functionality.</p>

<p>However, the first time I selected a photo, the sheet was presented, but its content displayed “No photo selected.” This was unexpected!</p>

<p>The ⁠isAskNamePresented variable is set after we assign the photo data to ⁠currentNamedPhoto, so the sheet should recognize that ⁠currentNamedPhoto is no longer nil.</p>

<p>Initially, I suspected that the code inside the ⁠Task was not executed sequentially, but I quickly dismissed this idea. Swift does not behave like Haskell in this regard.</p>

<p>Next, I considered whether the closure might be related to the issue, as the variable captured within the closure has value semantics. This means the value does not change, but I soon realized this assumption was incorrect.</p>

<p>After conducting some research, I found an explanation on StackOverflow: <a href="https://stackoverflow.com/questions/66262213/swiftui-sheet-unexpectedly-found-nil-while-unwrapping-an-optional-value/66267507#66267507">link</a>. It states that changes are ignored because the variable is not directly used within the ⁠body property, leading SwiftUI to optimize it out.</p>

<p>To resolve this, I updated the code by adding one line:</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">var</span> <span class="nv">body</span><span class="p">:</span> <span class="kd">some</span> <span class="kt">View</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">let</span> <span class="nv">currentNamedPhoto</span> <span class="o">=</span> <span class="n">currentNamedPhoto</span> <span class="p">{}</span>

        <span class="kt">PhotosPicker</span><span class="p">(</span><span class="s">"Select a photo"</span><span class="p">,</span> <span class="nv">selection</span><span class="p">:</span> <span class="err">$</span><span class="n">pickerItem</span><span class="p">,</span> <span class="nv">matching</span><span class="p">:</span> <span class="o">.</span><span class="n">images</span><span class="p">)</span>
<span class="c1">// ...</span>
</code></pre></div></div>

<p>Now, everything works as intended!</p>

<p>Alternatively, we can use another initializer for the sheet: <a href="https://developer.apple.com/documentation/swiftui/view/sheet(item:ondismiss:content:)">link</a></p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">struct</span> <span class="kt">ContentView</span><span class="p">:</span> <span class="kt">View</span> <span class="p">{</span>
    <span class="kd">@State</span> <span class="kd">private</span> <span class="k">var</span> <span class="nv">namedPhotos</span><span class="p">:</span> <span class="p">[</span><span class="kt">NamedPhoto</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="kd">@State</span> <span class="kd">private</span> <span class="k">var</span> <span class="nv">pickerItem</span><span class="p">:</span> <span class="kt">PhotosPickerItem</span><span class="p">?</span>
    <span class="kd">@State</span> <span class="kd">private</span> <span class="k">var</span> <span class="nv">currentNamedPhoto</span><span class="p">:</span> <span class="kt">NamedPhoto</span><span class="p">?</span> <span class="o">=</span> <span class="kc">nil</span>

    <span class="k">var</span> <span class="nv">body</span><span class="p">:</span> <span class="kd">some</span> <span class="kt">View</span> <span class="p">{</span>
        <span class="kt">PhotosPicker</span><span class="p">(</span><span class="s">"Select a photo"</span><span class="p">,</span> <span class="nv">selection</span><span class="p">:</span> <span class="err">$</span><span class="n">pickerItem</span><span class="p">,</span> <span class="nv">matching</span><span class="p">:</span> <span class="o">.</span><span class="n">images</span><span class="p">)</span>
            <span class="o">.</span><span class="nf">onChange</span><span class="p">(</span><span class="nv">of</span><span class="p">:</span> <span class="n">pickerItem</span><span class="p">)</span> <span class="p">{</span><span class="n">_</span><span class="p">,</span> <span class="n">newItem</span> <span class="k">in</span>
                <span class="kt">Task</span> <span class="p">{</span>
                    <span class="k">if</span> <span class="k">let</span> <span class="nv">data</span> <span class="o">=</span> <span class="k">try</span> <span class="k">await</span> <span class="n">newItem</span><span class="p">?</span><span class="o">.</span><span class="nf">loadTransferable</span><span class="p">(</span><span class="nv">type</span><span class="p">:</span> <span class="kt">Data</span><span class="o">.</span><span class="k">self</span><span class="p">)</span> <span class="p">{</span>
                        <span class="n">currentNamedPhoto</span> <span class="o">=</span> <span class="kt">NamedPhoto</span><span class="p">(</span><span class="nv">photo</span><span class="p">:</span> <span class="n">data</span><span class="p">,</span> <span class="nv">name</span><span class="p">:</span> <span class="s">""</span><span class="p">)</span>
                    <span class="p">}</span>
                <span class="p">}</span>
            <span class="p">}</span>
            <span class="o">.</span><span class="nf">sheet</span><span class="p">(</span><span class="nv">item</span><span class="p">:</span> <span class="err">$</span><span class="n">currentNamedPhoto</span><span class="p">,</span> <span class="nv">onDismiss</span><span class="p">:</span> <span class="p">{</span> <span class="p">})</span> <span class="p">{</span> <span class="n">item</span> <span class="k">in</span>
                <span class="k">var</span> <span class="nv">newItem</span> <span class="o">=</span> <span class="kt">NamedPhoto</span><span class="p">(</span><span class="nv">photo</span><span class="p">:</span> <span class="n">item</span><span class="o">.</span><span class="n">photo</span><span class="p">,</span> <span class="nv">name</span><span class="p">:</span> <span class="s">""</span><span class="p">)</span>
                <span class="nf">toImage</span><span class="p">(</span><span class="nv">from</span><span class="p">:</span> <span class="n">newItem</span><span class="o">.</span><span class="n">photo</span><span class="p">)</span>
                    <span class="o">.</span><span class="nf">resizable</span><span class="p">()</span>
                    <span class="o">.</span><span class="nf">scaledToFit</span><span class="p">()</span>
                    <span class="o">.</span><span class="nf">frame</span><span class="p">(</span><span class="nv">height</span><span class="p">:</span> <span class="mi">300</span><span class="p">)</span>
                <span class="kt">TextField</span><span class="p">(</span><span class="s">"Name"</span><span class="p">,</span> <span class="nv">text</span><span class="p">:</span> <span class="kt">Binding</span><span class="p">(</span><span class="nv">get</span><span class="p">:</span> <span class="p">{</span> <span class="n">newItem</span><span class="o">.</span><span class="n">name</span> <span class="p">},</span> <span class="nv">set</span><span class="p">:</span> <span class="p">{</span> <span class="n">newItem</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="nv">$0</span> <span class="p">}))</span>
                <span class="kt">Button</span><span class="p">(</span><span class="s">"Add"</span><span class="p">)</span> <span class="p">{</span>
                    <span class="n">namedPhotos</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="n">newItem</span><span class="p">)</span>
                    <span class="n">currentNamedPhoto</span> <span class="o">=</span> <span class="kc">nil</span>
                <span class="p">}</span>
            <span class="p">}</span>
<span class="c1">// ...</span>
</code></pre></div></div>

<p>This approach also works effectively.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[This issue arose from a project I was working on for the “100 Days of SwiftUI” challenge. The application allows users to select a photo from their library and assign a name to it. While it’s a simple app, it presented a puzzling challenge.]]></summary></entry><entry><title type="html">Swap Nodes in Pairs – Iterative vs Recursive</title><link href="https://guiyuanju.github.io/leetcode-24-swap-nodes-in-pairs.html" rel="alternate" type="text/html" title="Swap Nodes in Pairs – Iterative vs Recursive" /><published>2025-03-12T00:00:00+00:00</published><updated>2025-03-12T00:00:00+00:00</updated><id>https://guiyuanju.github.io/leetcode-24-swap-nodes-in-pairs</id><content type="html" xml:base="https://guiyuanju.github.io/leetcode-24-swap-nodes-in-pairs.html"><![CDATA[<p><a href="https://leetcode.com/problems/swap-nodes-in-pairs/">24. Swap Nodes in Pairs</a></p>

<p>Given a linked list, swap every two adjacent nodes and return its head. You must solve the problem without modifying the values in the list’s nodes (i.e., only nodes themselves may be changed.)</p>

<p>Example:
Input: head = [1,2,3,4]
Output: [2,1,4,3]</p>

<p>Iterative solution:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">swapPairs</span><span class="p">(</span><span class="n">head</span> <span class="o">*</span><span class="n">ListNode</span><span class="p">)</span> <span class="o">*</span><span class="n">ListNode</span> <span class="p">{</span>
	<span class="k">if</span> <span class="n">head</span> <span class="o">==</span> <span class="no">nil</span> <span class="o">||</span> <span class="n">head</span><span class="o">.</span><span class="n">Next</span> <span class="o">==</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">head</span>
	<span class="p">}</span>

	<span class="n">dump</span> <span class="o">:=</span> <span class="n">head</span><span class="o">.</span><span class="n">Next</span>
	<span class="k">var</span> <span class="n">prev</span> <span class="o">*</span><span class="n">ListNode</span>
	<span class="k">for</span> <span class="n">head</span> <span class="o">!=</span> <span class="no">nil</span> <span class="o">&amp;&amp;</span> <span class="n">head</span><span class="o">.</span><span class="n">Next</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="k">if</span> <span class="n">prev</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
			<span class="n">prev</span><span class="o">.</span><span class="n">Next</span> <span class="o">=</span> <span class="n">head</span><span class="o">.</span><span class="n">Next</span>
		<span class="p">}</span>
		<span class="n">next</span> <span class="o">:=</span> <span class="n">head</span><span class="o">.</span><span class="n">Next</span><span class="o">.</span><span class="n">Next</span>
		<span class="n">head</span><span class="o">.</span><span class="n">Next</span><span class="o">.</span><span class="n">Next</span> <span class="o">=</span> <span class="n">head</span>
		<span class="n">head</span><span class="o">.</span><span class="n">Next</span> <span class="o">=</span> <span class="n">next</span>

		<span class="n">prev</span> <span class="o">=</span> <span class="n">head</span>
		<span class="n">head</span> <span class="o">=</span> <span class="n">head</span><span class="o">.</span><span class="n">Next</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="n">dump</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Recursive solution:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">swapPairs</span><span class="p">(</span><span class="n">head</span> <span class="o">*</span><span class="n">ListNode</span><span class="p">)</span> <span class="o">*</span><span class="n">ListNode</span> <span class="p">{</span>
	<span class="k">if</span> <span class="n">head</span> <span class="o">==</span> <span class="no">nil</span> <span class="o">||</span> <span class="n">head</span><span class="o">.</span><span class="n">Next</span> <span class="o">==</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">head</span>
	<span class="p">}</span>

	<span class="n">dump</span> <span class="o">:=</span> <span class="n">head</span><span class="o">.</span><span class="n">Next</span>
	<span class="n">next</span> <span class="o">:=</span> <span class="n">head</span><span class="o">.</span><span class="n">Next</span><span class="o">.</span><span class="n">Next</span>
	<span class="n">head</span><span class="o">.</span><span class="n">Next</span><span class="o">.</span><span class="n">Next</span> <span class="o">=</span> <span class="n">head</span>
	<span class="n">head</span><span class="o">.</span><span class="n">Next</span> <span class="o">=</span> <span class="n">swapPairs</span><span class="p">(</span><span class="n">next</span><span class="p">)</span>
	<span class="k">return</span> <span class="n">dump</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Im my opinion, the recursive solution is much more easily to come up with and understand.</p>]]></content><author><name></name></author><category term="leetcode" /><category term="linked_list" /><summary type="html"><![CDATA[24. Swap Nodes in Pairs]]></summary></entry><entry><title type="html">Default Parameters in Python</title><link href="https://guiyuanju.github.io/python-default-parameters.html" rel="alternate" type="text/html" title="Default Parameters in Python" /><published>2024-06-20T00:00:00+00:00</published><updated>2024-06-20T00:00:00+00:00</updated><id>https://guiyuanju.github.io/Python-Default-Parameters</id><content type="html" xml:base="https://guiyuanju.github.io/python-default-parameters.html"><![CDATA[<p>Consider the following class:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">LineCollector</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">lines</span><span class="o">=</span><span class="p">[]):</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">lines</span> <span class="o">=</span> <span class="n">lines</span>

    <span class="k">def</span> <span class="nf">collect</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">line</span><span class="p">):</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">lines</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>

<span class="n">c1</span> <span class="o">=</span> <span class="n">LineCollector</span><span class="p">()</span>
<span class="n">c2</span> <span class="o">=</span> <span class="n">LineCollector</span><span class="p">()</span>

<span class="n">c1</span><span class="p">.</span><span class="n">collect</span><span class="p">(</span><span class="s">"Hi mom"</span><span class="p">)</span>
<span class="n">c2</span><span class="p">.</span><span class="n">collect</span><span class="p">(</span><span class="s">"Are you ok Annie?"</span><span class="p">)</span>

<span class="k">print</span><span class="p">(</span><span class="n">c1</span><span class="p">.</span><span class="n">lines</span><span class="p">)</span>
</code></pre></div></div>

<p>What output would you expect?</p>

<p>The result is:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="s">'Hi mom'</span><span class="p">,</span> <span class="s">'Are you ok Annie?'</span><span class="p">]</span>
</code></pre></div></div>

<p>Surprising right? As a programmer who are new to Python, I am very confused by this behavior. The mechanism behind it is:</p>

<ol>
  <li>Python evaluate the default value only once when it come across the def statement</li>
  <li>Every subsequent call uses the same pre-evaluated default object.</li>
</ol>

<p>Someone mentioned that this behavior can actually be useful for capturing a variable’s value inside a loop:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">fs</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">f</span><span class="p">():</span>
        <span class="k">print</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
    <span class="n">fs</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>

<span class="p">[</span><span class="n">f</span><span class="p">()</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">fs</span><span class="p">]</span>
</code></pre></div></div>

<p>It prints out 10 ‘9’s, with this feature, the following program print 0 to 9 correctly:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">fs</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">i</span><span class="o">=</span><span class="n">i</span><span class="p">):</span>
        <span class="k">print</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
    <span class="n">fs</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>

<span class="p">[</span><span class="n">f</span><span class="p">()</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">fs</span><span class="p">]</span>
</code></pre></div></div>

<p>Alternatively, we can use a closure like this, though it’s a bit more complex:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">fs</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">i</span><span class="p">):</span>
        <span class="k">return</span> <span class="k">lambda</span><span class="p">:</span> <span class="p">(</span><span class="k">print</span><span class="p">(</span><span class="n">i</span><span class="p">))</span>
    <span class="n">fs</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">f</span><span class="p">(</span><span class="n">i</span><span class="p">))</span>

<span class="p">[</span><span class="n">f</span><span class="p">()</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">fs</span><span class="p">]</span>
</code></pre></div></div>

<p>This problem actually reminds me of the similar for loop variable capture problem in Go, which is fixed in Go 1.22 https://go.dev/blog/loopvar-preview</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Consider the following class:]]></summary></entry><entry><title type="html">Expression Problem</title><link href="https://guiyuanju.github.io/expression-problem.html" rel="alternate" type="text/html" title="Expression Problem" /><published>2023-02-22T00:00:00+00:00</published><updated>2023-02-22T00:00:00+00:00</updated><id>https://guiyuanju.github.io/Expression-Problem</id><content type="html" xml:base="https://guiyuanju.github.io/expression-problem.html"><![CDATA[<p>OOP (Object-Oriented Programming) and FP (Functional Programming) are two prominent programming paradigms today, each offering distinct advantages and facing unique challenges. A classical example illustrating their differences is the expression problem.</p>

<p>The <strong>expression problem</strong> is concerned with extensibility regarding operations and types. Consider a type called number, which has two subtypes: int and float, along with two operations: + and -. This can be represented in a table of implementations:</p>

<table>
  <thead>
    <tr>
      <th>Operation / Type</th>
      <th><code class="language-plaintext highlighter-rouge">int</code></th>
      <th><code class="language-plaintext highlighter-rouge">float</code></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">+</code></td>
      <td>…</td>
      <td>…</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">-</code></td>
      <td>…</td>
      <td>…</td>
    </tr>
  </tbody>
</table>

<p><strong>OOP Perspective</strong></p>

<p>In an OOP language like Java, number is defined as an interface with methods for + and -. The int and float types are classes implementing this interface. Adding a new subtype, such as a complex class representing complex numbers, is straightforward. You simply create the new class and implement the necessary methods without altering the existing code for int and float, thus avoiding recompilation.</p>

<p>However, adding a new operation, like _ (multiply), becomes challenging. You must locate the code for int, float, and complex, add the _ method, and recompile all affected classes. This process can be time-consuming and error-prone.</p>

<p><strong>FP Perspective</strong></p>

<p>In an FP language like Haskell, number is a user-defined union type with constructors for int and float. Operations like + and - are defined as functions using case structures to handle each type variant. Adding a new operation, such as *, is simple; you just define a new function without modifying the type definition.</p>

<p>However, introducing a new type variant, like complex, requires modifying all functions defined on the number type, which can be cumbersome.</p>

<p><strong>Complementary Strengths and Weaknesses</strong></p>

<p>From this discussion, we see that OOP and FP have complementary strengths and weaknesses. OOP focuses on grouping operations into classes, making it easy to add new classes, while FP groups operations into functions, facilitating the addition of new operations.</p>

<p>When modeling real-world problems, which often evolve, it can be challenging to anticipate future needs. Is there a way to achieve extensibility for both operations and types? Yes, several methods exist:</p>

<ol>
  <li><strong>Multiple Dispatch</strong></li>
</ol>

<p>Multiple dispatch (or multi-methods) dispatches function implementations based on all of their arguments, unlike the single dispatch common in OOP languages like Java, which determines method implementation based solely on the receiver. Multiple dispatch is open, allowing users to extend existing multi-methods from third-party packages without modifying them. Adding an operation requires defining multiple multi-methods for existing types, while adding a new type necessitates creating multi-methods for both the new type and existing types. CLOS (Common Lisp Object System) is a well-known example of multiple dispatch.</p>

<ol>
  <li><strong>Open Classes</strong></li>
</ol>

<p>Open classes, often found in dynamic languages like Ruby, allow users to dynamically add methods to existing classes without modifying the original code. This flexibility enhances extensibility.</p>

<ol>
  <li><strong>Type Classes</strong></li>
</ol>

<p>Haskell employs type classes to address the expression problem. A type class defines the necessary “abstract” or “virtual” methods required for any type belonging to that class. Operations are defined based on these abstractions. Adding a new type simply involves implementing the required abstractions for the type class, allowing existing operations to remain unchanged.</p>

<p><strong>Observer Pattern</strong></p>

<p>Notably, the <strong>observer pattern</strong> is a design pattern that shifts a program’s focus from types to operations. This transition allows for the exchange of advantages and disadvantages between OOP and FP, but it does not resolve the expression problem; rather, it transitions the problem from the OOP side to the FP side.</p>

<p>In summary, while OOP and FP each have their strengths and weaknesses regarding extensibility, various techniques can help achieve a balance, allowing for both operations and types to be extended more easily.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[OOP (Object-Oriented Programming) and FP (Functional Programming) are two prominent programming paradigms today, each offering distinct advantages and facing unique challenges. A classical example illustrating their differences is the expression problem.]]></summary></entry></feed>