<?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="http://nekoboxcoder.dev/feed.xml" rel="self" type="application/atom+xml" /><link href="http://nekoboxcoder.dev/" rel="alternate" type="text/html" /><updated>2026-07-11T18:42:21+00:00</updated><id>http://nekoboxcoder.dev/feed.xml</id><title type="html">Neko-Box-Coder</title><subtitle>Just my personal stuff</subtitle><entry><title type="html">Classic C++ std library trap (Function overloading + brace initialization)</title><link href="http://nekoboxcoder.dev/programming/c++/2026/07/11/classic-c++-std-library-trap-function-overloading+-brace-initialization.html" rel="alternate" type="text/html" title="Classic C++ std library trap (Function overloading + brace initialization)" /><published>2026-07-11T00:00:00+00:00</published><updated>2026-07-11T00:00:00+00:00</updated><id>http://nekoboxcoder.dev/programming/c++/2026/07/11/classic-c++-std-library-trap-function-overloading+-brace-initialization</id><content type="html" xml:base="http://nekoboxcoder.dev/programming/c++/2026/07/11/classic-c++-std-library-trap-function-overloading+-brace-initialization.html"><![CDATA[<p>Previously, I was talking about how <a href="/programming/c/c++/yapping/2026/07/05/yapping-about-code-philosophy.html#prefer-simple-explicitly-imperative-code">simple explicit imperative code should be preferred over 
implicit ones</a>.
Funny enough, I have quickly encountered a perfect example for it.</p>

<p>I was working on <a href="https://github.com/Neko-Box-Coder/runcpp2">runcpp2</a> yaml parsing logic using 
<a href="https://github.com/yaml/libyaml">libyaml</a>, which I have encountered an out-of-bound access when 
testing a feature. I was initially quite surprised by this given the line above <strong>has just</strong> added 
the element to that said position. Here’s the offending (simplified) code, see if you can spot 
anything weird.</p>

<p><sub><sub><strong>Not a challenge/trick question by any means</strong></sub></sub></p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//Simpified code, roughly</span>
<span class="k">struct</span> <span class="nc">Node</span><span class="p">;</span>
<span class="k">using</span> <span class="n">Sequence</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">Node</span><span class="o">&gt;&gt;</span><span class="p">;</span>
<span class="k">struct</span> <span class="nc">Node</span>
<span class="p">{</span>
    <span class="n">mpark</span><span class="o">::</span><span class="n">variant</span><span class="o">&lt;</span><span class="n">StringView</span><span class="p">,</span> <span class="n">Alias</span><span class="p">,</span> <span class="n">Sequence</span><span class="p">,</span> <span class="n">OrderedMap</span><span class="o">&gt;</span> <span class="n">Value</span> <span class="o">=</span> <span class="s">""</span><span class="p">;</span>
    <span class="p">...</span>
<span class="p">};</span>

<span class="kr">inline</span> <span class="n">std</span><span class="o">::</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">Node</span><span class="o">&gt;</span> <span class="n">Node</span><span class="o">::</span><span class="n">CreateSequenceChildAt</span><span class="p">(</span><span class="kt">uint32_t</span> <span class="n">index</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">DS_ASSERT_TRUE</span><span class="p">(</span><span class="n">mpark</span><span class="o">::</span><span class="n">is</span><span class="o">&lt;</span><span class="n">Sequence</span><span class="o">&gt;</span><span class="p">(</span><span class="n">Value</span><span class="p">));</span>                     <span class="c1">//The variant has `Sequence`</span>
    <span class="n">DS_ASSERT_LT_EQ</span><span class="p">(</span><span class="n">index</span><span class="p">,</span> <span class="n">mpark</span><span class="o">::</span><span class="n">get</span><span class="o">&lt;</span><span class="n">Sequence</span><span class="o">&gt;</span><span class="p">(</span><span class="n">Value</span><span class="p">).</span><span class="n">size</span><span class="p">());</span>     <span class="c1">//We are inserting to a valid index</span>
    
    <span class="cp">#if 1
</span>        <span class="c1">//Inserting a nullptr at index position</span>
        <span class="n">mpark</span><span class="o">::</span><span class="n">get</span><span class="o">&lt;</span><span class="n">Sequence</span><span class="o">&gt;</span><span class="p">(</span><span class="n">Value</span><span class="p">).</span><span class="n">insert</span><span class="p">(</span><span class="n">mpark</span><span class="o">::</span><span class="n">get</span><span class="o">&lt;</span><span class="n">Sequence</span><span class="o">&gt;</span><span class="p">(</span><span class="n">Value</span><span class="p">).</span><span class="n">begin</span><span class="p">()</span> <span class="o">+</span> <span class="n">index</span><span class="p">,</span> <span class="p">{});</span>
    <span class="cp">#else
</span>        <span class="c1">//The code below is the same as the above line, not in actual codebase</span>
        <span class="n">Sequence</span><span class="o">&amp;</span> <span class="n">s</span> <span class="o">=</span> <span class="n">mpark</span><span class="o">::</span><span class="n">get</span><span class="o">&lt;</span><span class="n">Sequence</span><span class="o">&gt;</span><span class="p">(</span><span class="n">Value</span><span class="p">);</span>
        <span class="n">s</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="n">s</span><span class="p">.</span><span class="n">begin</span><span class="p">()</span> <span class="o">+</span> <span class="n">index</span><span class="p">,</span> <span class="p">{});</span>
    <span class="cp">#endif
</span>    
    <span class="k">return</span> <span class="n">mpark</span><span class="o">::</span><span class="n">get</span><span class="o">&lt;</span><span class="n">Sequence</span><span class="o">&gt;</span><span class="p">(</span><span class="n">Value</span><span class="p">)[</span><span class="n">index</span><span class="p">];</span>  <span class="c1">//&lt;-- Out of bound access!!!!</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This happened in one of the test where it was trying to add a node to the end of the vector 
(<code class="language-plaintext highlighter-rouge">std::vector&lt;std::shared_ptr&lt;Node&gt;&gt;</code>) (And yes, I know, I am using the std library. This code was 
before I have a <em>strong</em> opinion against C++ and std library).</p>

<p>At first I couldn’t believe what I was seeing, I have used <code class="language-plaintext highlighter-rouge">std::vector</code> so many times, I thought I 
know what most of the functions do, this 4 lines of code looks fine to me.</p>

<p>Then I was thinking, could it be the iterator? For example, maybe</p>
<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">uint32_t</span> <span class="n">index</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="p">...</span><span class="o">&gt;::</span><span class="n">size</span><span class="p">();</span>
<span class="kt">bool</span> <span class="n">eq</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="p">...</span><span class="o">&gt;::</span><span class="n">begin</span><span class="p">()</span> <span class="o">+</span> <span class="n">index</span> <span class="o">==</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="p">...</span><span class="o">&gt;::</span><span class="n">end</span><span class="p">();</span>
<span class="c1">//eq is not guaranteed to be true?...</span>
</code></pre></div></div>

<p>But they should be the same, from my memory. I checked if they are the same by assigning them to 
temporary variables and inspecting the iterator <sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>. They are the same, 
<code class="language-plaintext highlighter-rouge">std::vector&lt;...&gt;::begin() + index</code> and <code class="language-plaintext highlighter-rouge">std::vector&lt;...&gt;::end()</code> are pointing to the same address.</p>

<p>Okay, could it be <code class="language-plaintext highlighter-rouge">std::vector&lt;...&gt;::insert()</code> doesn’t allow you to use <code class="language-plaintext highlighter-rouge">std::vector&lt;...&gt;::end()</code> 
as the insert position? So I go to cppreference and look at the documentation:</p>

<blockquote>
  <p>From https://en.cppreference.com/cpp/container/vector/insert</p>
  <div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">iterator</span> <span class="nf">insert</span><span class="p">(</span> <span class="n">const_iterator</span> <span class="n">pos</span><span class="p">,</span> <span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">value</span> <span class="p">);</span>                        <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</code></pre></div>  </div>
  <p>[…]</p>

  <p>Parameters</p>
  <ul>
    <li>pos - iterator before which the content will be inserted (pos may be the end() iterator)</li>
    <li>value - element value to insert</li>
    <li>[…]</li>
  </ul>
</blockquote>

<p>Okay. The documentation literally specifies <code class="language-plaintext highlighter-rouge">end()</code> is allowed as <code class="language-plaintext highlighter-rouge">pos</code>. So what could it be…</p>

<p>I have decided to stop guessing around and step through the code in the debugger and see what is it 
doing inside <code class="language-plaintext highlighter-rouge">insert()</code>.</p>

<p>When I was running in the debugger, this is what the code looks like inside <code class="language-plaintext highlighter-rouge">insert()</code>.</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 *  @brief  Inserts an initializer_list into the %vector.
 *  @param  __position  An iterator into the %vector.
 *  @param  __l  An initializer_list.
 *
 *  This function will insert copies of the data in the
 *  initializer_list @a l into the %vector before the location
 *  specified by @a position.
 *
 *  Note that this kind of operation could be expensive for a
 *  %vector and if it is frequently used the user should
 *  consider using std::list.
 */</span>
<span class="n">_GLIBCXX20_CONSTEXPR</span>
<span class="n">iterator</span>
<span class="nf">insert</span><span class="p">(</span><span class="n">const_iterator</span> <span class="n">__position</span><span class="p">,</span> <span class="n">initializer_list</span><span class="o">&lt;</span><span class="n">value_type</span><span class="o">&gt;</span> <span class="n">__l</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">auto</span> <span class="n">__offset</span> <span class="o">=</span> <span class="n">__position</span> <span class="o">-</span> <span class="n">cbegin</span><span class="p">();</span>
    <span class="n">_M_range_insert</span><span class="p">(</span><span class="n">begin</span><span class="p">()</span> <span class="o">+</span> <span class="n">__offset</span><span class="p">,</span> <span class="n">__l</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">__l</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span>
                    <span class="n">std</span><span class="o">::</span><span class="n">random_access_iterator_tag</span><span class="p">());</span>
    <span class="k">return</span> <span class="n">begin</span><span class="p">()</span> <span class="o">+</span> <span class="n">__offset</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>where the signature of <code class="language-plaintext highlighter-rouge">_M_range_insert</code> is this:</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">_GLIBCXX20_CONSTEXPR</span>
<span class="kt">void</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">_Tp</span><span class="p">,</span> <span class="n">_Alloc</span><span class="o">&gt;::</span><span class="n">_M_range_insert</span><span class="p">(</span><span class="n">iterator</span> <span class="n">__position</span><span class="p">,</span> <span class="n">_ForwardIterator</span> <span class="n">__first</span><span class="p">,</span>
                                          <span class="n">_ForwardIterator</span> <span class="n">__last</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">forward_iterator_tag</span><span class="p">);</span>
</code></pre></div></div>

<p>Noticed anything weird? When I was stepping through, only when I was in <code class="language-plaintext highlighter-rouge">_M_range_insert()</code> and I 
realized… “Wait, this is not the function I want to call, is it?”</p>

<p>Indeed, it is a bit odd that a function called <code class="language-plaintext highlighter-rouge">_M_range_insert()</code> is called with first and last 
iterators when only a single item is needed to be inserted.</p>

<p>Turns out, I have called the 5th overload variant which is</p>
<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">iterator</span> <span class="nf">insert</span><span class="p">(</span> <span class="n">const_iterator</span> <span class="n">pos</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">initializer_list</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">ilist</span> <span class="p">);</span>              <span class="p">(</span><span class="mi">5</span><span class="p">)</span>
</code></pre></div></div>

<p>where it accepts a list of items to be added.</p>

<p>So basically, when I called</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">s</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="n">s</span><span class="p">.</span><span class="n">begin</span><span class="p">()</span> <span class="o">+</span> <span class="n">index</span><span class="p">,</span> <span class="p">{});</span>
</code></pre></div></div>

<p>The 5th <code class="language-plaintext highlighter-rouge">insert()</code> variant “takes precedence” over the default initializer of the <code class="language-plaintext highlighter-rouge">std::shared_ptr</code> 
which means I inserted <em>nothing</em>. And therefore the subsequent access</p>
<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">return</span> <span class="n">s</span><span class="p">[</span><span class="n">index</span><span class="p">];</span>  <span class="c1">//&lt;-- Out of bound access!!!!</span>
</code></pre></div></div>
<p>fails because it thought the item was inserted.</p>

<p>I put “takes precedence” in quotes because, to me this is might as well an arbitrary decision made 
by the compiler because it thinks it knows what the programmer (I) want.</p>

<p>Another example to code things in C / C style C++, honestly.</p>

<hr />

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>Difficult to do in <code class="language-plaintext highlighter-rouge">gdb</code> because it will always show you the element it is pointing to when you do <code class="language-plaintext highlighter-rouge">print</code> (it recognizes it’s one of the stdlib containers and treat it differently), but doable with a magic trick of spamming tab. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name></name></author><category term="programming" /><category term="c++" /><category term="programming" /><category term="c++" /><summary type="html"><![CDATA[Previously, I was talking about how simple explicit imperative code should be preferred over implicit ones. Funny enough, I have quickly encountered a perfect example for it.]]></summary></entry><entry><title type="html">Yapping About Code Abstractions</title><link href="http://nekoboxcoder.dev/programming/c/yapping/2026/07/06/yapping-about-code-abstractions.html" rel="alternate" type="text/html" title="Yapping About Code Abstractions" /><published>2026-07-06T00:00:00+00:00</published><updated>2026-07-06T00:00:00+00:00</updated><id>http://nekoboxcoder.dev/programming/c/yapping/2026/07/06/yapping-about-code-abstractions</id><content type="html" xml:base="http://nekoboxcoder.dev/programming/c/yapping/2026/07/06/yapping-about-code-abstractions.html"><![CDATA[<h3 id="explicit-abstractions-over-implicit-abstractions-no-need-to-hide-implementations">Explicit abstractions over implicit abstractions, no need to hide implementations</h3>

<p>Just like every thing in life, some abstractions are good, some are bad.</p>

<p>One common mistake that I see people do ALL THE TIME is trying to over simplify, over abstract or 
over generalize things away from the end user.</p>

<p>For example, imagine you are tasked to design a bespoke storage service for storing/retrieving a 
custom binary data block format that has a mixture of arbitrary text metadata and video binary data 
in it where it is normally quite large. Therefore, it is fine to read/write one data block at a time.</p>

<p>Some people would over complicate things and think, “We are using X as a backend right now, but what
if we change that in the future and store it to the cloud? What if we use the filesystem directly? 
What if…”. Some other people might think, “The user should only concern about what they want to 
store or get, they shouldn’t care what’s going on under the hood because we are handling everything 
for them.”. Either way,</p>

<p>This would likely be what many people will come up with:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">DataBlock</span><span class="p">;</span>
<span class="k">typedef</span> <span class="k">struct</span> <span class="n">DataBlock</span> <span class="n">DataBlock</span><span class="p">;</span>
<span class="k">struct</span> <span class="n">Storage</span><span class="p">;</span> <span class="c1">//Called `Storage` because it _might_ not be a database</span>
<span class="k">typedef</span> <span class="k">struct</span> <span class="n">Storage</span> <span class="n">Storage</span><span class="p">;</span>

<span class="n">bool</span> <span class="nf">SaveDataBlock</span><span class="p">(</span><span class="n">Storage</span><span class="o">*</span> <span class="n">storage</span><span class="p">,</span> <span class="n">DataBlock</span><span class="o">*</span> <span class="n">dataBlock</span><span class="p">);</span>
<span class="n">DataBlock</span><span class="o">*</span> <span class="nf">GetDataBlock</span><span class="p">(</span><span class="n">Storage</span><span class="o">*</span> <span class="n">storage</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">query</span><span class="p">);</span>   <span class="c1">//Returns NULL if not found</span>
</code></pre></div></div>

<p>Seems good enough right? After all, this does everything the user needed.</p>

<p><sub><em>I am no database expert and here’s what it could look like. But you don’t have to read it.</em></sub></p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">bool</span> <span class="nf">SaveDataBlock</span><span class="p">(</span><span class="n">Storage</span><span class="o">*</span> <span class="n">storage</span><span class="p">,</span> <span class="n">DataBlock</span><span class="o">*</span> <span class="n">dataBlock</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">storage</span> <span class="o">||</span> <span class="o">!</span><span class="n">dataBlock</span><span class="p">)</span>
        <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
    
    <span class="c1">//A video should be at least 1 MB, otherwise something wrong</span>
    <span class="k">if</span><span class="p">(</span><span class="n">GetVideoByteSize</span><span class="p">(</span><span class="n">dataBlock</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">1024</span> <span class="o">*</span> <span class="mi">1024</span><span class="p">)</span>
        <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
    
    <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">binaryPath</span> <span class="o">=</span> <span class="n">WriteBinaryDataToDisk</span><span class="p">(</span><span class="n">dataBlock</span><span class="p">);</span>  <span class="c1">//Write to an unique path</span>
    <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">binaryPath</span><span class="p">)</span>
        <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
    
    <span class="c1">//Transaction is just a list of actions to be performed atomicly</span>
    <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">transactionPath</span> <span class="o">=</span> <span class="n">StartTransaction</span><span class="p">();</span>
    <span class="p">{</span>
        <span class="k">if</span><span class="p">(</span> <span class="o">!</span><span class="n">WriteMetadataToTransaction</span><span class="p">(</span><span class="n">dataBlock</span><span class="p">,</span> <span class="n">binaryPath</span><span class="p">,</span> <span class="n">transactionPath</span><span class="p">)</span> <span class="o">||</span>
            <span class="c1">//We need the database to not change before we do indexing and apply it</span>
            <span class="o">!</span><span class="n">LockDatabase</span><span class="p">(</span><span class="n">storage</span><span class="p">,</span> <span class="nb">false</span> <span class="cm">/*is read?*/</span><span class="p">)</span> <span class="o">||</span>
            <span class="o">!</span><span class="n">UpdateExistingIndexToTransaction</span><span class="p">(</span><span class="n">storage</span><span class="p">,</span> <span class="n">query</span><span class="p">,</span> <span class="n">transactionPath</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="k">goto</span> <span class="n">failed</span><span class="p">;</span>
        <span class="p">}</span>
        
        <span class="n">EndTransaction</span><span class="p">(</span><span class="n">transactionPath</span><span class="p">);</span>
        <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">ApplyTransaction</span><span class="p">(</span><span class="n">storage</span><span class="p">,</span> <span class="n">transactionPath</span><span class="p">))</span>    <span class="c1">//Atomic operation</span>
            <span class="k">goto</span> <span class="n">failed</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">UnlockDatabase</span><span class="p">(</span><span class="n">storage</span><span class="p">);</span>
    <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
    
    <span class="nl">failed:</span><span class="p">;</span>
    <span class="n">UnlockDatabase</span><span class="p">(</span><span class="n">storage</span><span class="p">);</span>
    <span class="n">DiscardTransaction</span><span class="p">(</span><span class="n">transactionPath</span><span class="p">);</span>
    <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">DataBlock</span><span class="o">*</span> <span class="nf">GetDataBlock</span><span class="p">(</span><span class="n">Storage</span><span class="o">*</span> <span class="n">storage</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">query</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">storage</span> <span class="o">||</span> <span class="o">!</span><span class="n">query</span><span class="p">)</span>
        <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
    
    <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">LockDatabase</span><span class="p">(</span><span class="n">storage</span><span class="p">,</span> <span class="nb">true</span> <span class="cm">/*is read?*/</span><span class="p">))</span>
        <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
    
    <span class="n">DataBlock</span><span class="o">*</span> <span class="n">retDataBlock</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
    
    <span class="c1">//Update index if needed</span>
    <span class="n">AttributesList</span> <span class="n">attributesThatNeedIndexing</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">};</span>
    <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">GetAttributesRequireIndexing</span><span class="p">(</span><span class="n">storage</span><span class="p">,</span> <span class="n">query</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">attributesThatNeedIndexing</span><span class="p">))</span>
        <span class="k">goto</span> <span class="n">cleanup</span><span class="p">;</span>
    
    <span class="k">if</span><span class="p">(</span><span class="n">attributesThatNeedIndexing</span><span class="p">.</span><span class="n">Length</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">//We need to add new index to database</span>
        <span class="n">UnlockDatabase</span><span class="p">(</span><span class="n">storage</span><span class="p">);</span>
        
        <span class="c1">//Relock it again with write access</span>
        <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">LockDatabase</span><span class="p">(</span><span class="n">storage</span><span class="p">,</span> <span class="nb">false</span> <span class="cm">/*is read?*/</span><span class="p">))</span>
            <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
        
        <span class="c1">//Refresh the list again since something could have changed between unlock and lock</span>
        <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">GetAttributesRequireIndexing</span><span class="p">(</span><span class="n">storage</span><span class="p">,</span> <span class="n">query</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">attributesThatNeedIndexing</span><span class="p">))</span>
            <span class="k">goto</span> <span class="n">cleanup</span><span class="p">;</span>
        
        <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">transactionPath</span> <span class="o">=</span> <span class="n">StartTransaction</span><span class="p">();</span>
        <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">AddIndexToTransaction</span><span class="p">(</span><span class="n">storage</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">attributesThatNeedIndexing</span><span class="p">,</span> <span class="n">transactionPath</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="n">DiscardTransaction</span><span class="p">(</span><span class="n">transactionPath</span><span class="p">);</span>
            <span class="k">goto</span> <span class="n">cleanup</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">EndTransaction</span><span class="p">(</span><span class="n">transactionPath</span><span class="p">);</span>
        <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">ApplyTransaction</span><span class="p">(</span><span class="n">storage</span><span class="p">,</span> <span class="n">transactionPath</span><span class="p">))</span>    <span class="c1">//Atomic operation</span>
        <span class="p">{</span>
            <span class="n">DiscardTransaction</span><span class="p">(</span><span class="n">transactionPath</span><span class="p">);</span>
            <span class="k">goto</span> <span class="n">cleanup</span><span class="p">;</span>
        <span class="p">}</span>
        
        <span class="n">UnlockDatabase</span><span class="p">(</span><span class="n">storage</span><span class="p">);</span>
        <span class="c1">//Relock it again with read access</span>
        <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">LockDatabase</span><span class="p">(</span><span class="n">storage</span><span class="p">,</span> <span class="nb">true</span> <span class="cm">/*is read?*/</span><span class="p">))</span>
            <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="p">}</span>
    
    <span class="n">Node</span> <span class="n">entry</span> <span class="o">=</span> <span class="n">QueryNextEntry</span><span class="p">(</span><span class="n">storage</span><span class="p">,</span> <span class="n">q</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span> <span class="c1">//Find the first entry</span>
    <span class="k">if</span><span class="p">(</span><span class="n">entry</span><span class="p">.</span><span class="n">Valid</span><span class="p">)</span>
        <span class="n">retDataBlock</span> <span class="o">=</span> <span class="n">getDataBlockFromNode</span><span class="p">(</span><span class="o">&amp;</span><span class="n">entry</span><span class="p">);</span>
    
    <span class="nl">cleanup:</span><span class="p">;</span>
    <span class="n">UnlockDatabase</span><span class="p">(</span><span class="n">storage</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">retDataBlock</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Just like what they were designed to, most of the inner workings such as handling multi-read, 
single write locking, validating video size (&gt; 1MB), adding/updating indexes, atomic udpates, etc…
are all hidden away from the user.</p>

<p>Additionally, it is very common for all of the struct pointers to be just opaque pointers and the 
database functions not exposed at all as well. Therefore the user doesn’t even know if it is a 
database.</p>

<p>This interface works fine for simple use case and a few users that perform read most of the time.</p>

<p>… Except <strong>it isn’t</strong>. Because the users have no idea how it works under the hood, they are likely 
to query with a <strong>generous amount</strong> of attributes filters, resulting the need of creating many 
indexes in the database</p>

<p>This means the size and processing time explodes as the number of data blocks increases.</p>

<p>Also, if you think about the requirement for a bit longer, you might have noticed something odd.</p>

<blockquote>
  <p>[…] design a bespoke storage service for <strong>storing/retrieving</strong> a custom binary data block format […]</p>
</blockquote>

<p>Unsurprisingly, the requirement <strong>forgot</strong> to mention the ability to <strong>remove</strong> a stored data. 
And they need it quick because some users started to create data blocks by mistake and other users 
are getting these wrong data blocks.</p>

<p>They <em>could</em> get around this by creating a dummy data block with a custom metadata attribute that 
flags the stale data blocks, like this:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">Metadata</span><span class="pi">:</span>
    <span class="na">UUID</span><span class="pi">:</span> <span class="m">123</span>
    <span class="s">...</span>
    <span class="na">Staled_UUID</span><span class="pi">:</span> <span class="m">345</span>
<span class="na">Binary</span><span class="pi">:</span> 
    <span class="s">&lt;video data ...&gt;</span>
</code></pre></div></div>

<p>And check if the data block we got is staled or not by doing something like</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">DataBlock</span><span class="o">*</span> <span class="n">queriedDataBlock</span> <span class="o">=</span> <span class="n">GetDataBlock</span><span class="p">(</span><span class="n">storage</span><span class="p">,</span> <span class="s">"UUID == 345"</span><span class="p">);</span>
<span class="k">if</span><span class="p">(</span><span class="n">queriedDataBlock</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">DataBlock</span><span class="o">*</span> <span class="n">staled</span> <span class="o">=</span> <span class="n">GetDataBlock</span><span class="p">(</span><span class="n">storage</span><span class="p">,</span> <span class="s">"Staled_UUID == 345"</span><span class="p">);</span>
    <span class="k">if</span><span class="p">(</span><span class="n">staled</span><span class="p">)</span>
        <span class="k">return</span> <span class="p">...;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>While this works (although not ideal), it will be slow everytime we mark/check a data block is 
staled because…</p>

<blockquote>
  <p>[…] most of the inner workings such as […] <strong>validating video size (&gt; 1MB)</strong> […] are all 
hidden away from the user.</p>
</blockquote>

<p>Meaning when we create a dummy data block, we will need to satisfy the video size to make it “valid”.</p>

<p>So each time we want to mark something as staled, we are storing 1 MB of dummy video data and we are 
reading &amp; copying 1 MB of dummy video data each time we want to check a given data block is staled or 
not.</p>

<p>You might say these all seem a bit artificial and cherry picked, but this happens all the time when 
the stated requirement deviate from the expectation for various reasons.</p>

<p>There’s more:</p>

<ol>
  <li>Now what if there’s an user who wants to store/get many data blocks with a short video? The 
locking and updating of the indexes each time will slow the rest of the users to a halt.
    <ul>
      <li><strong>Let’s create a batch specify version of the API functions which operates on multiple data 
 blocks at a time.</strong></li>
    </ul>
  </li>
  <li>Okay. Now turns out all of our users so far are storing MP4 (compressed) videos, and a new user 
wants to store an AVI video (less compressed) instead. The moment we are trying to store/retrieve 
this video, it blocks the rest of the user because it is so much larger than a normal video.
    <ul>
      <li><strong>Let’s create a multi-part version of the API functions and spread these multi-part functions 
 so that it doesn’t block the rest of the users.</strong></li>
    </ul>
  </li>
  <li>Now what if there’s a write heavy/frequent user? Each time there’s a write, it needs to lock the 
whole database. This means the no reads can be done when there’s a write each time and therefore the 
read requests will pile up.
    <ul>
      <li><strong>Let’s adjust the internal implementation to group reads and writes at a time for non critical 
 requests.</strong></li>
    </ul>
  </li>
</ol>

<p>All of this leads to my point of, requirements change all the time, niche cases happen all the time. 
Each time any of these happen, the API needs to be changed, the implementation needs to be changed.</p>

<blockquote>
  <h4 id="the-user-is-powerless-because-everything-is-abstracted-hidden-away">The user is powerless because everything is abstracted, hidden away.</h4>
</blockquote>

<p>So, how should it be fixed?</p>

<p>To approach this question, first we need to understand that people <strong>RARELY</strong> get their public API 
right the first time. There’s always something missing and there’s always some niche use cases that 
we will never think of.</p>

<p>So instead of hiding everything away from the user, we should be exposing the internal functions as 
much as possible alongside the main, intended public API, as long as the internal ones  are clearly 
labeled so.</p>

<p>They don’t <strong>have</strong> to be API/ABI stable because they are intended as internal functions, but 
reserving some fields in a struct and a handful of parameters goes a long way, even for main public 
API functions, not just the internal ones.</p>

<p>I will actually go one step further and say the user should always know and have access to internal 
functions as much as possible.</p>

<p>What you <strong>REALLY</strong> want is to treat the “original” public API functions as “helper functions” or 
“default options” to the “lower level” functions. Like this:</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="n">DataBlock</span>
<span class="p">{</span>
    <span class="c1">//Internal Fields...</span>
<span class="p">}</span> <span class="n">DataBlock</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="n">Database</span>
<span class="p">{</span>
    <span class="c1">//Internal Fields...</span>
<span class="p">}</span> <span class="n">Database</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="n">Options</span>
<span class="p">{</span>
    <span class="n">bool</span> <span class="n">LockDatabase</span><span class="p">;</span>
    <span class="n">bool</span> <span class="n">UpdateIndexes</span><span class="p">;</span>
    <span class="p">...</span>
    <span class="kt">uint8_t</span> <span class="n">Reserves</span><span class="p">[</span><span class="mi">32</span><span class="p">];</span>
<span class="p">}</span> <span class="n">Options</span><span class="p">;</span>

<span class="c1">//Public API Function</span>
<span class="n">Options</span> <span class="nf">CreateDefaultOptions</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>     <span class="c1">//Returns a default options object that fit the main use case</span>
<span class="n">bool</span> <span class="nf">SaveDataBlock</span><span class="p">(</span><span class="n">Database</span><span class="o">*</span> <span class="n">db</span><span class="p">,</span> <span class="n">DataBlock</span><span class="o">*</span> <span class="n">dataBlock</span><span class="p">,</span> <span class="n">Options</span> <span class="n">options</span><span class="p">);</span>
<span class="n">DataBlock</span><span class="o">*</span> <span class="nf">GetDataBlock</span><span class="p">(</span><span class="n">Database</span><span class="o">*</span> <span class="n">db</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">query</span><span class="p">,</span> <span class="n">Options</span> <span class="n">options</span><span class="p">);</span>   <span class="c1">//Returns NULL if not found</span>
    
<span class="c1">//Internal "Low Level" Functions</span>
<span class="n">bool</span> <span class="nf">LockDatabase</span><span class="p">(</span><span class="n">Database</span><span class="o">*</span> <span class="n">db</span><span class="p">,</span> <span class="n">bool</span> <span class="n">readOnly</span><span class="p">);</span>
<span class="kt">void</span> <span class="n">UnlockDatabse</span><span class="p">(</span><span class="n">Database</span><span class="o">*</span> <span class="n">db</span><span class="p">)</span>
<span class="c1">//...</span>
<span class="c1">//Transaction functions...</span>
<span class="c1">//Database functions...</span>
<span class="c1">//...</span>
</code></pre></div></div>

<p>Basically, for the public API functions, the default options should be enough for the majority of 
the use cases.</p>

<p>The <code class="language-plaintext highlighter-rouge">Options</code> struct along with the “low level” functions should give the users pretty good idea on 
what the public API functions are doing under the hood, should they care.</p>

<p>If the default options do not satisfy the user’s use case, they have the ability to tinker with 
various options to see if that solves their problem.</p>

<p>If even that is not enough, the user has access to “low level” functions that they can use for their 
very niche use case, in which case they should be aware that internal functions are subject to change 
in the future.</p>]]></content><author><name></name></author><category term="programming" /><category term="c" /><category term="yapping" /><category term="programming" /><category term="c" /><category term="yapping" /><summary type="html"><![CDATA[Explicit abstractions over implicit abstractions, no need to hide implementations]]></summary></entry><entry><title type="html">Yapping About The Right Way of Programming</title><link href="http://nekoboxcoder.dev/programming/c/c++/yapping/2026/07/05/yapping-about-code-philosophy.html" rel="alternate" type="text/html" title="Yapping About The Right Way of Programming" /><published>2026-07-05T00:00:00+00:00</published><updated>2026-07-05T00:00:00+00:00</updated><id>http://nekoboxcoder.dev/programming/c/c++/yapping/2026/07/05/yapping-about-code-philosophy</id><content type="html" xml:base="http://nekoboxcoder.dev/programming/c/c++/yapping/2026/07/05/yapping-about-code-philosophy.html"><![CDATA[<p><em>This is taken and modified from my 
<a href="https://github.com/Neko-Box-Coder/SimpleCodingStyle">SimpleCodingStyle</a> repository.</em></p>

<p>This applies to most languages, not just c/c++.</p>

<h3 id="keep-it-simple-stupid">Keep it simple, stupid</h3>
<p>Things are always changing, new deadlines, new features, new requirements.</p>

<p>Instead of spending time over-engineering and designing something that you don’t know how it will 
work out (and you never will, unless you can predict the future), get it working first. After that
you can do whatever you want, refactor it, clean it, etc.</p>

<p>Nothing is future proof and don’t waste your time trying to pretend you will design something 
future proof. Something “good enough” is often the right balance between how much time is spent on
designing the architecture and implementation to allow changes if needed.</p>

<h3 id="priority-readability-and-iterability-over-pre-mature-optimization">Priority readability and iterability over pre-mature optimization</h3>
<p>This of course is different per context/scenarios, but generally languages are fast enough under 
most use-cases, and performance often only matters under certain part of a program (i.e. a hot loop).</p>

<p>Sacrificing readability and iterability (i.e. Trying to reduce a small copy by reusing a variable 
but makes the code harder to read) on non performance critical part isn’t worth it.</p>

<p>That is not to say you should make it inefficient, small habits like adding <code class="language-plaintext highlighter-rouge">const</code> and using 
pointer/reference is generally good to do and doesn’t hurt readability.</p>

<p>A good rule of thumb is “Make it easy to read first, then make it run faster”</p>

<h3 id="no-inheritance-no-oop-no-interface-no-clean-code-no-solid">No Inheritance, No OOP, No Interface, No “Clean Code”, No “SOLID”</h3>
<p>The mainstream really endorse OOP. Schools, corporates, books are all praising it because it is 
“Battle Tested” and is the industry de facto, not knowing how painfully confusing to navigate 
and difficult to add features to these codebase. Not to mention it is slower as well, see 
<a href="https://www.youtube.com/watch?v=tD5NrevFtbU">“Clean” Code, Horrible Performance</a> by Casey Muratori.</p>

<p>Here by OOP I mean <strong>object inheritance and interfaces</strong>, not functions that are binded to 
a data structure, not RAII.</p>

<p>OOP sounds great on paper, you re-use things with hierarchical design, isolation of concerns and 
allow easy testing. But in practice it often falls short in terms of readability and iterability.</p>

<p>Trying to follow through a flow on what a function does? Too bad you will have to go to 20 
different files to understand which concrete functions <strong>can</strong> be called, not to mention there
can be <strong>more than 1</strong> concrete functions can be called if it is a multi-layer inheritance.</p>

<p>Using interfaces to make it easier for testing? Good luck diving through many layers and wrappers 
when you are trying to debug or read the code, only to find out the logic is a dynamic 
delegate/function object that is spawned and configured somewhere else and you now have to find 
where that is. Also good luck adding new features since the moment you change the interface, 
you are forced to update 20 other classes (and tests) that are dependent on that interface.</p>

<p>Of course “Clean Code” and “SOLID” says none of these are an issue if you follow their rules.
This will be true if we live in a perfect world where there are no deadlines, no change of 
requirements, no unique new features, no special use cases from the customer, etc.</p>

<p>But we don’t live in a perfect world, this is just a lie so that people can sell books and host 
talks and the only people can do this are big corporations which can afford to this and the rest
of us are wasting time trying to perfect something that is always imperfect.</p>

<p>I have been to <a href="https://github.com/Neko-Box-Coder/ssGUI">this</a> 
<a href="https://github.com/Neko-Box-Coder/CppOverride">path</a> (Using OOP) and <strong>DEEPLY</strong> regretted it.</p>

<p>Just implement the damn thing.</p>

<h3 id="composition-if-and-switch-statements">Composition, If and Switch Statements</h3>

<p>Instead of OOP and all those shit, just use composition, good ol’ if statements and switch 
statements when you need to generalize something. Not only it is easier to read since now each 
function in the generalization shows <strong>EXACTLY</strong> what concrete functions it will call, it is easier
to debug as well since you can can access all the concrete data just by poking into the member 
data structure.</p>

<h3 id="prefer-simple-explicitly-imperative-code">Prefer Simple, Explicitly Imperative Code</h3>

<p>Whenever possible, I normally avoid language features that do things implicitly or in a non-obvious 
way. In C++, this includes the following:</p>
<ul>
  <li>Constructor &amp; destructor</li>
  <li>Operator overloading</li>
  <li>Implicit conversion</li>
  <li>Throwing exceptions</li>
  <li>Relying on things like RVO or NVRO</li>
  <li>Inheritance</li>
</ul>

<p>For other languages like python, decorators would be another example on something to be avoided.</p>

<p>Let me give you an example:</p>
<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//C++</span>
<span class="n">String</span> <span class="n">myString</span> <span class="o">=</span> <span class="n">GetDateTimeText</span><span class="p">();</span>
</code></pre></div></div>

<p>Depending on how <code class="language-plaintext highlighter-rouge">String</code> and <code class="language-plaintext highlighter-rouge">GetDateTimeText()</code> are defined, this single line can do various 
things.</p>

<ul>
  <li>If <code class="language-plaintext highlighter-rouge">String</code> is just a simple C struct, the values in from <code class="language-plaintext highlighter-rouge">GetDateTimeText()</code> will just be 
copied/assigned to <code class="language-plaintext highlighter-rouge">myString</code>.</li>
  <li>If <code class="language-plaintext highlighter-rouge">String</code> has constructor or destructor defined, they might be called multiple depending on how 
<code class="language-plaintext highlighter-rouge">GetDataTimeText()</code> constructs and returns it, which can allocate/deallocate memory.</li>
  <li>If <code class="language-plaintext highlighter-rouge">String</code>  has <code class="language-plaintext highlighter-rouge">String&amp; operator=(String&amp; other)</code> defined, it might not only copy the raw data 
in the struct, but also copy all the data this struct is pointing to as well. This is totally 
up to the user defined implemenation.</li>
  <li>If <code class="language-plaintext highlighter-rouge">String</code> has <code class="language-plaintext highlighter-rouge">String&amp; operator=(String&amp;&amp; other)</code> defined, it might copy and invalidate 
the pointer in the returned struct instead of copying all the data this struct is pointing to, 
again depending how <code class="language-plaintext highlighter-rouge">GetDataTimeText()</code> is defined. Again, totally up to the user defined 
implemenation.</li>
  <li>If <code class="language-plaintext highlighter-rouge">String</code> has an implicit conversion defined (say <code class="language-plaintext highlighter-rouge">StringView</code>), which is user defined, 
could be triggered as well if <code class="language-plaintext highlighter-rouge">GetDataTimeText()</code> returns a different type. Not to mention now the 
behavior <strong>also</strong> depends on that implicit conversion type is defined as well.</li>
</ul>

<p>Also, having any combinations of the above, preset or not preset might also change the behavior too.</p>

<p>If a C++ codebase uses any of the above, you will find yourself having to look at the definitions of 
these just to figure out the behavior of this single line.</p>

<p>The problem is not <em>what</em> logic or code do any of these run, the problem is knowing <strong>when</strong> will a 
logic or code run, without having to go to different part of the codebase.</p>

<p>In a C or C style C++ codebase, this line will always do one thing only - copy whatever values in the 
returned <code class="language-plaintext highlighter-rouge">String</code> from <code class="language-plaintext highlighter-rouge">GetDateTimeText()</code> to <code class="language-plaintext highlighter-rouge">myString</code>, that’s it.</p>

<p>Some people might say it’s “skill” issue, but I disagree. All of these things I mentioned are 
abstracted concepts that enable specific ways or patterns of modelling logic and resource 
management. These “concepts” raise the bar for beginners or programmers from another language to 
work on a codebase, and it is difficult to figure out because they are so implicit.</p>

<hr />

<p>Every time when I work on a codebase with any of the problems I mentioned in this post, I am losing 
my sanity on how difficult it is to figure out what a piece of code do exactly.</p>

<p>Please, for the love of god, just keep things simple.</p>]]></content><author><name></name></author><category term="programming" /><category term="c" /><category term="c++" /><category term="yapping" /><category term="programming" /><category term="c" /><category term="c++" /><category term="yapping" /><summary type="html"><![CDATA[This is taken and modified from my SimpleCodingStyle repository.]]></summary></entry></feed>