<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="/feeds/atom-style.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://astro-chiri.netlify.app</id>
    <title>C's-BLOG</title>
    <updated>2026-05-27T13:35:12.384Z</updated>
    <generator>Astro Chiri Feed Generator</generator>
    <author>
        <name>3ASH</name>
        <uri>https://astro-chiri.netlify.app</uri>
    </author>
    <link rel="alternate" href="https://astro-chiri.netlify.app"/>
    <link rel="self" href="https://astro-chiri.netlify.app/atom.xml"/>
    <subtitle>Minimal blog built by Astro</subtitle>
    <rights>Copyright © 2026 3ASH</rights>
    <entry>
        <title type="html"><![CDATA[Not all for loops are created equal]]></title>
        <id>https://astro-chiri.netlify.app/blog/no-for-loop-created-equal</id>
        <link href="https://astro-chiri.netlify.app/blog/no-for-loop-created-equal"/>
        <updated>2026-01-31T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>If you’ve written code in more than one language, you’ve likely noticed that <code>for</code> loops look strikingly similar across the board. Whether it’s <code>for x in list</code> or <code>foreach (var x in list)</code>, the syntax suggests a universal constant: <strong>iteration is iteration</strong>.</p>
<p>But beneath the syntax sugar lies one of the foundational design forks in programming language theory: <strong>ownership during iteration</strong>.</p>
<p>When you write a loop, the language runtime has to make a critical decision about the data you are accessing. It must decide whether to give you a copy of the data, a reference to the data, or something in between. This isn’t just an implementation detail; it defines the performance characteristics, safety guarantees, and bug classes of your entire application.</p>
<p>In this post, I want to dissect these iteration models and explore why the “same” loop compiles down to very different contract with memory.</p>
<h2>Omni-present syntax, Divergent semantics</h2>
<p>Let’s look at the hidden question every loop answers: <em>What exactly is the loop variable?</em></p>
<p>Is it a <strong>copy</strong>? A <strong>reference</strong>? A <strong>borrow</strong>?</p>
<h3>1. Value Iteration (Go)</h3>
<p>In Go, iterating over a slice with <code>range</code> defaults to providing a copy of the value.</p>
<pre><code class="language-go">for _, v := range slice {
    v.field = "changed" // Modifies the copy, not the original
}
</code></pre>
<p>This model defaults to <strong>safety via isolation</strong>. Because <code>v</code> is a copy, you cannot accidentally mutate the underlying collection or cause spooky action-at-a-distance. The memory model is simple: iteration creates new stack-allocated values.</p>
<p><strong>The Trade-off</strong>:</p>
<ul>
<li><strong>Pros</strong>: It eliminates an entire class of aliasing bugs.</li>
<li><strong>Cons</strong>: It incurs a hidden performance penalty. If your slice contains large structs, every iteration triggers a <code>memcpy</code>, which can silently kill throughput in hot paths.</li>
</ul>
<h3>2. Reference Iteration (Python, JavaScript, Java)</h3>
<p>Contrast this with the model favored by high-level managed languages. In Python or JavaScript, the loop variable is a <strong>reference</strong> (or pointer) to the object in the heap.</p>
<pre><code class="language-python">for user in users:
    user.name = "X" # Modifies the original object
</code></pre>
<p>Here, the language prioritizes <strong>ergonomics and zero-copy</strong>. You are working directly with the data.</p>
<p><strong>The Trade-off</strong>:</p>
<ul>
<li><strong>Pros</strong>: It’s performant by default regarding memory bandwidth (no copying).</li>
<li><strong>Cons</strong>: It introduces <strong>implicit aliasing</strong>. A mutation inside a loop updates the state “globally” for anyone holding a reference to that object. This creates the classic concurrency nightmare: if another thread touches <code>users</code> while you are iterating, you have a race condition.</li>
</ul>
<h3>3. Borrowed Iteration (Rust)</h3>
<p>Rust takes a third path, exposing the memory model directly in the syntax. It forces you to choose the contract you want with the data using its ownership system.</p>
<pre><code class="language-rust">for user in &amp;users {}     // Immutable borrow: Read-only access
for user in &amp;mut users {} // Mutable borrow: Exclusive write access
for user in users {}      // Move: Transfer ownership (consume collection)
</code></pre>
<p>Ideally, this is the “correct” solution from a systems perspective. It provides the zero-cost benefits of Reference Iteration without the safety hazards.</p>
<p>However, it introduces <strong>friction</strong>. The borrow checker will strictly enforce that you cannot mutate the collection <em>structure</em> (like pushing/popping) while iterating over it—a common source of iterator invalidation bugs in C++.</p>
<h2>The Universal Baseline: Index Iteration</h2>
<p>When abstractions fail, every language allows you to fall back to the raw, C-style access pattern:</p>
<pre><code class="language-go">for i := 0; i &lt; len(slice); i++ {
    slice[i] = mutate(slice[i])
}
</code></pre>
<p>This is <strong>Index Iteration</strong>. It is the ultimate “trust me” mode. It bypasses iterator protocols entirely, giving you precise control over memory access at the cost of safety (off-by-one errors) and readability.</p>
<h2>Conclusion</h2>
<p>The loop isn’t just a control flow structure; it’s a window into the language’s philosophy.</p>
<table>
<thead>
<tr>
<th>Language</th>
<th>Default Model</th>
<th>Philosophy</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Go</strong></td>
<td>Value (Copy)</td>
<td>Simple mental model, safety &gt; raw perf</td>
</tr>
<tr>
<td><strong>Python</strong></td>
<td>Reference</td>
<td>Developer velocity, implicitness</td>
</tr>
<tr>
<td><strong>Rust</strong></td>
<td>Borrow/Move</td>
<td>Explicit ownership, zero-cost safety</td>
</tr>
</tbody>
</table>
<p>Next time you type <code>for</code>, pause and ask: <strong>Who owns this data?</strong> The answer might save you from a production bug down the line.</p>
]]></content>
        <published>2026-01-31T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[How HTTP routing really works ]]></title>
        <id>https://astro-chiri.netlify.app/blog/routing-no-framework</id>
        <link href="https://astro-chiri.netlify.app/blog/routing-no-framework"/>
        <updated>2026-01-03T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>We have all handled routes in our web applications — the familiar <code>/users</code>, <code>/blog</code>,
and similar endpoints. Most of us learned routing through frameworks like
Express:</p>
<pre><code class="language-js">const express = require("express");
const app = express();
const port = 3000;

app.get("/", (req, res) =&gt; {
  res.send("Hello World!");
});

app.listen(port, () =&gt; {
  console.log(`Example app listening on port ${port}`);
});
</code></pre>
<p>This snippet starts an HTTP server on port 3000 and registers a handler for the
/ route. It is popular for a reason: it is simple, expressive, and hides a large
amount of complexity behind a clean API.</p>
<p>But underneath this simplicity, a web server is still just a program that reads
and writes bytes over a network socket. Express is not “magic” — it is a
carefully engineered system that sits on top of TCP and implements the HTTP
protocol, routing, middleware, parsing, and response handling for you.</p>
<p>In this article, we will peel away those abstractions and build a very small
HTTP router directly on top of a raw TCP stream.</p>
<p>To be precise: we are not “routing TCP.” Routing is an HTTP-level concept. TCP
only provides a stream of bytes. Our job will be to interpret those bytes as an
HTTP request and then choose a handler based on the request’s method and path.</p>
<h2>What Really Happens Inside a Web Server?</h2>
<p>At a high level, every HTTP server follows this pipeline:
<img src="https://astro-chiri.netlify.app/routing.png" alt="Routing" /></p>
<p>Frameworks like Express implement this entire pipeline for you. We will
implement a minimal version of the same idea ourselves.</p>
<p>The goal is not to replace Express — it is to understand what it is actually
doing under the hood.</p>
<h1>A Minimal TCP-Based HTTP Router in Rust</h1>
<p>A TCP connection gives us nothing more than a stream of bytes. If we want
routing, we must:</p>
<div class="flex flex-col gap-4 my-8 items-center not-prose">
  <div class="bg-gray-100 dark:bg-gray-800 p-4 rounded-lg border border-gray-200 dark:border-gray-700 w-full max-w-md text-center shadow-sm">
    <span class="font-mono text-sm text-gray-500 block mb-1">Step 1</span>
    Read bytes from the socket
  </div>
  <div class="text-gray-400">
    
  </div>
  <div class="bg-gray-100 dark:bg-gray-800 p-4 rounded-lg border border-gray-200 dark:border-gray-700 w-full max-w-md text-center shadow-sm">
    <span class="font-mono text-sm text-gray-500 block mb-1">Step 2</span>
    Interpret them as an HTTP request
  </div>
  <div class="text-gray-400">
    
  </div>
  <div class="bg-gray-100 dark:bg-gray-800 p-4 rounded-lg border border-gray-200 dark:border-gray-700 w-full max-w-md text-center shadow-sm">
    <span class="font-mono text-sm text-gray-500 block mb-1">Step 3</span>
    Inspect the method and path
  </div>
  <div class="text-gray-400">
    
  </div>
  <div class="bg-gray-100 dark:bg-gray-800 p-4 rounded-lg border border-gray-200 dark:border-gray-700 w-full max-w-md text-center shadow-sm">
    <span class="font-mono text-sm text-gray-500 block mb-1">Step 4</span>
    Dispatch to the appropriate handler
  </div>
</div>
<p>Here is a minimal teaching implementation:</p>
<pre><code class="language-rs">fn handle_client(mut stream: TcpStream) { let mut buffer = [0; 1024];

    match stream.read(&amp;mut buffer) {
        Ok(size) =&gt; {
            let request = String::from_utf8_lossy(&amp;buffer[..size]);

            let (status_line, content) = match &amp;*request {
                r if r.starts_with("POST /users") =&gt; handle_post_request(r),
                r if r.starts_with("GET /users/") =&gt; handle_get_request(r),
                r if r.starts_with("GET /users") =&gt; handle_get_all_request(r),
                r if r.starts_with("DELETE /users/") =&gt; handle_delete_request(r),
                _ =&gt; (NOT_FOUND.to_string(), "Not Found".to_string()),
            };

            let response = format!("{}{}", status_line, content);

            if let Err(e) = stream.write_all(response.as_bytes()) {
                eprintln!("Failed to send response: {}", e);
            }
        }
        Err(e) =&gt; eprintln!("Error reading from stream: {}", e),
    }

}
</code></pre>
<p>Let’s break down exactly what is happening in this code.</p>
<h3>1. Reading from the Socket</h3>
<pre><code class="language-rs">let mut buffer = [0; 1024];
match stream.read(&amp;mut buffer) { ... }
</code></pre>
<p>We create a fixed-size buffer of 1024 bytes and try to read data from the <code>TcpStream</code>. This is where we get the raw bytes sent by the client (your browser).</p>
<h3>2. Converting Bytes to String</h3>
<pre><code class="language-rs">let request = String::from_utf8_lossy(&amp;buffer[..size]);
</code></pre>
<p>The browser sends bytes, but we need text to make routing decisions. <code>String::from_utf8_lossy</code> converts the raw bytes into a Rust <code>String</code>. If there are invalid UTF-8 sequences, it replaces them with  instead of crashing.</p>
<h3>3. The Routing Logic (Pattern Matching)</h3>
<pre><code class="language-rs">let (status_line, content) = match &amp;*request {
    r if r.starts_with("POST /users") =&gt; handle_post_request(r),
    r if r.starts_with("GET /users/") =&gt; handle_get_request(r),
    r if r.starts_with("GET /users") =&gt; handle_get_all_request(r),
    r if r.starts_with("DELETE /users/") =&gt; handle_delete_request(r),
    _ =&gt; (NOT_FOUND.to_string(), "Not Found".to_string()),
};
</code></pre>
<p>This <code>match</code> block is the core <strong>Router</strong>. It inspects the <code>request</code> string to see if it starts with a specific method and path combo (like <code>"GET /users"</code>).</p>
<ul>
<li>If it matches, it delegates to a specific handler function (e.g., <code>handle_get_request</code>).</li>
<li>If no patterns match, it defaults to the <code>_</code> case, returning a <strong>404 Not Found</strong>.</li>
</ul>
<h3>4. Sending the Response</h3>
<pre><code class="language-rs">let response = format!("{}{}", status_line, content);
stream.write_all(response.as_bytes())
</code></pre>
<p>Finally, we take the result from the handler (the status line and the content), combine them into a single HTTP response string, and write the bytes back to the socket.</p>
<hr />
<blockquote>
<p>[!NOTE]
<strong>This Is a Teaching Implementation</strong></p>
<p>This code is intentionally naive:</p>
<ul>
<li>HTTP requests can be larger than 1024 bytes.</li>
<li><code>read()</code> is not guaranteed to return the full request in one go.</li>
<li>Real servers must handle partial reads, buffering, persistent connections, and full HTTP parsing.</li>
<li>A real router parses the <strong>request line</strong> and <strong>headers</strong> properly instead of using simple string prefix matching.</li>
</ul>
<p>Despite these limitations, this implementation exposes the core idea: <strong>routing is just structured decision-making over bytes read from a TCP socket.</strong></p>
</blockquote>
]]></content>
        <published>2026-01-03T00:00:00.000Z</published>
    </entry>
</feed>