<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.4">Jekyll</generator><link href="https://scp-iota.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://scp-iota.github.io/" rel="alternate" type="text/html" /><updated>2026-06-02T22:35:54+00:00</updated><id>https://scp-iota.github.io/feed.xml</id><title type="html">SCP-iota</title><subtitle>Open-sorcerer, trans girl, memetic hazard</subtitle><entry><title type="html">Rust dyn-Compatibility Proxying</title><link href="https://scp-iota.github.io/software/2026/01/20/rust-dyn-compatibility-proxying.html" rel="alternate" type="text/html" title="Rust dyn-Compatibility Proxying" /><published>2026-01-20T00:00:00+00:00</published><updated>2026-01-20T00:00:00+00:00</updated><id>https://scp-iota.github.io/software/2026/01/20/rust-dyn-compatibility-proxying</id><content type="html" xml:base="https://scp-iota.github.io/software/2026/01/20/rust-dyn-compatibility-proxying.html"><![CDATA[<p>If you’re fairly familiar with Rust, you’ve probably seen and used <code class="language-plaintext highlighter-rouge">dyn</code> trait objects: references to values that implement specific traits without knowledge of the concrete underlying type. For example, <code class="language-plaintext highlighter-rouge">Box&lt;dyn std::error::Error&gt;</code> is a frequent go-to error type when you don’t want to mess with breaking down every possible error type that could be returned by a function. Trait objects are intended for more than convenience, though; they give you the flexibility to mix and swap out underlying implementations of a trait at runtime.</p>

<p>For example, a codebase that accesses a database through a layer of abstraction will likely have a trait for the overall data connection - say, <code class="language-plaintext highlighter-rouge">DataRoot</code> - that could have multiple concrete implementations for different database server protocols. If there was no expectation of being able to select or change the specific implementation of <code class="language-plaintext highlighter-rouge">DataRoot</code> at runtime, then code could pass around a <code class="language-plaintext highlighter-rouge">&amp;mut impl DataRoot</code> and avoid the need for dynamic trait objects. However, if, say, the application takes a command-line argument that selects between different database backends, and can even load plugins that can register new database backend types, then the application’s codebase cannot rely on the concrete implementation of <code class="language-plaintext highlighter-rouge">DataRoot</code> being known at compile-time; instead, all it can know is that the type implements <code class="language-plaintext highlighter-rouge">DataRoot</code> and the specifics are only determined at runtime. That is precisely what <code class="language-plaintext highlighter-rouge">dyn</code> trait objects are meant for, so ideally, the codebase could pass around a <code class="language-plaintext highlighter-rouge">&amp;mut dyn DataRoot</code>.</p>

<p>The problem arises when <code class="language-plaintext highlighter-rouge">DataRoot</code> needs to use features that prevent it from being <code class="language-plaintext highlighter-rouge">dyn</code>-compatible. <code class="language-plaintext highlighter-rouge">dyn</code>-compatibility refers to whether a trait can be represented as a vtable, which is required for using it as a trait object, since <code class="language-plaintext highlighter-rouge">dyn</code> references internally hold a vtable pointer used for dispatching method calls. There are various things that can prevent a trait from being <code class="language-plaintext highlighter-rouge">dyn</code>-compatible, but in this case, we’ll focus on one particular common reason: a trait is not <code class="language-plaintext highlighter-rouge">dyn</code>-compatible if any of its methods have generic type parameters.</p>

<p>Practically speaking, that means we can’t use <code class="language-plaintext highlighter-rouge">impl ...</code> for parameters or return types without breaking <code class="language-plaintext highlighter-rouge">dyn</code>-compatibility, since such parameters are just syntax sugar for having generic type parameters for the concrete types being passed. Going back to the database example, suppose <code class="language-plaintext highlighter-rouge">DataRoot</code> has methods that return data access objects for specific types of resources. For example, say we have a <code class="language-plaintext highlighter-rouge">User</code> trait that represents access to a user record, and <code class="language-plaintext highlighter-rouge">DataRoot</code> has a <code class="language-plaintext highlighter-rouge">get_user</code> method to get a User by ID. If we didn’t need to concern ourselves with <code class="language-plaintext highlighter-rouge">dyn</code>-compatibility, that would likely look something like this:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="n">User</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">id</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">u64</span><span class="p">;</span>
    <span class="c1">// ...</span>
<span class="p">}</span>

<span class="k">trait</span> <span class="n">DataRoot</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">get_user</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">id</span><span class="p">:</span> <span class="nb">u64</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">impl</span> <span class="n">User</span><span class="p">;</span>
    <span class="c1">// ...</span>
<span class="p">}</span>
</code></pre></div></div>

<p>(For those wondering why <code class="language-plaintext highlighter-rouge">get_user</code> takes a mutable <code class="language-plaintext highlighter-rouge">self</code> - that’s because, if the implementation involves communicating with a backend server, the connection object likely requires mutable access to write to the socket. For now, we’re assuming this method blocks, but realistically, it should be <code class="language-plaintext highlighter-rouge">async</code>; I’m saving <code class="language-plaintext highlighter-rouge">Future</code>s for a, well… future, installment of this topic.)</p>

<p>This would work if the concrete type implementing <code class="language-plaintext highlighter-rouge">DataRoot</code> were known at compile-time, but we can’t create a <code class="language-plaintext highlighter-rouge">dyn DataRoot</code> because it has a method that breaks <code class="language-plaintext highlighter-rouge">dyn</code>-compatibility: <code class="language-plaintext highlighter-rouge">get_user</code> returns a <code class="language-plaintext highlighter-rouge">impl ...</code> type, which is just a generic type parameter under the hood. Alternatively, we could make it <code class="language-plaintext highlighter-rouge">dyn</code>-compatible by changing the return type to <code class="language-plaintext highlighter-rouge">Box&lt;dyn DataRoot&gt;</code>, but that would mean using dynamic trait objects even in code where the concrete implementation could reasonably be known at compile-time. That’s not ideal, since we’d lose optimizations like inlining, making zero-cost abstractions impossible with this setup. The goal is to devise a way for the concrete type to be known at compile-time whenever possible, allowing more optimizations, while also providing a way to use the trait dynamically when the implementation can only be known at runtime. The only apparent way forward is to have a separate version of the trait that is kept <code class="language-plaintext highlighter-rouge">dyn</code>-compatible:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="n">DataRoot</span><span class="o">&lt;</span><span class="nv">'l</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">get_user</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">id</span><span class="p">:</span> <span class="nb">u64</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">impl</span> <span class="n">User</span> <span class="o">+</span> <span class="nv">'l</span><span class="p">;</span>
    <span class="c1">// ...</span>
<span class="p">}</span>

<span class="k">trait</span> <span class="n">DataRootDyn</span><span class="o">&lt;</span><span class="nv">'l</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">get_user_dyn</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">id</span><span class="p">:</span> <span class="nb">u64</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Box</span><span class="o">&lt;</span><span class="k">dyn</span> <span class="n">User</span> <span class="o">+</span> <span class="nv">'l</span><span class="o">&gt;</span><span class="p">;</span>
    <span class="c1">// ...</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="nv">'l</span><span class="p">,</span> <span class="n">T</span><span class="p">:</span> <span class="n">DataRoot</span><span class="o">&lt;</span><span class="nv">'l</span><span class="o">&gt;&gt;</span> <span class="n">DataRootDyn</span><span class="o">&lt;</span><span class="nv">'l</span><span class="o">&gt;</span> <span class="k">for</span> <span class="n">T</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">get_user_dyn</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">id</span><span class="p">:</span> <span class="nb">u64</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Box</span><span class="o">&lt;</span><span class="k">dyn</span> <span class="n">User</span> <span class="o">+</span> <span class="nv">'l</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="nn">Box</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="k">self</span><span class="nf">.get_user</span><span class="p">(</span><span class="n">id</span><span class="p">))</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Here, we give a blanket implementation of <code class="language-plaintext highlighter-rouge">DataRootDyn</code> for any type that implements <code class="language-plaintext highlighter-rouge">DataRoot</code>, allowing us to simply implement <code class="language-plaintext highlighter-rouge">DataRoot</code> for a type and get a corresponding <code class="language-plaintext highlighter-rouge">DataRootDyn</code> implementation for free. The second half of this will allow the holder of a <code class="language-plaintext highlighter-rouge">dyn DataRootDyn</code> to call its methods as if it were a regular <code class="language-plaintext highlighter-rouge">DataRoot</code>, since we don’t want the dynamic separatism to be contagious throughout the codebase and require a second version of everything. We can do this by implementing <code class="language-plaintext highlighter-rouge">DataRoot</code> for the dynamic trait objects:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span><span class="o">&lt;</span><span class="nv">'l</span><span class="o">&gt;</span> <span class="n">DataRoot</span><span class="o">&lt;</span><span class="nv">'l</span><span class="o">&gt;</span> <span class="k">for</span> <span class="k">dyn</span> <span class="n">DataRootDyn</span><span class="o">&lt;</span><span class="nv">'l</span><span class="o">&gt;</span> <span class="o">+</span> <span class="nv">'l</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">get_user</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">id</span><span class="p">:</span> <span class="nb">u64</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">impl</span> <span class="n">User</span> <span class="o">+</span> <span class="nv">'l</span> <span class="p">{</span>
        <span class="k">self</span><span class="nf">.get_user_dyn</span><span class="p">(</span><span class="n">id</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="nv">'l</span><span class="p">,</span> <span class="n">T</span><span class="p">:</span> <span class="nb">AsMut</span><span class="o">&lt;</span><span class="k">dyn</span> <span class="n">DataRootDyn</span><span class="o">&lt;</span><span class="nv">'l</span><span class="o">&gt;</span> <span class="o">+</span> <span class="nv">'l</span><span class="o">&gt;&gt;</span> <span class="n">DataRoot</span><span class="o">&lt;</span><span class="nv">'l</span><span class="o">&gt;</span> <span class="k">for</span> <span class="n">T</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">get_user</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">id</span><span class="p">:</span> <span class="nb">u64</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">impl</span> <span class="n">User</span> <span class="o">+</span> <span class="nv">'l</span> <span class="p">{</span>
        <span class="k">self</span><span class="nf">.as_mut</span><span class="p">()</span><span class="nf">.get_user_dyn</span><span class="p">(</span><span class="n">id</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>We implement it for both the plain dynamic type and any types that implement <code class="language-plaintext highlighter-rouge">AsMut</code> for the dynamic type, so that we can call <code class="language-plaintext highlighter-rouge">DataRoot</code>’s methods on smart pointers like <code class="language-plaintext highlighter-rouge">Box&lt;dyn DataRootDyn&gt;</code>. For this to work, though, we also need the returned trait, <code class="language-plaintext highlighter-rouge">User</code>, to be implemented for its own <code class="language-plaintext highlighter-rouge">dyn</code> reference types, so we’ll do something similar for it:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span><span class="o">&lt;</span><span class="nv">'l</span><span class="p">,</span> <span class="n">T</span><span class="p">:</span> <span class="nb">AsRef</span><span class="o">&lt;</span><span class="k">dyn</span> <span class="n">User</span> <span class="o">+</span> <span class="nv">'l</span><span class="o">&gt;&gt;</span> <span class="n">User</span> <span class="k">for</span> <span class="n">T</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">id</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">u64</span> <span class="p">{</span>
        <span class="k">self</span><span class="nf">.as_ref</span><span class="p">()</span><span class="nf">.id</span><span class="p">()</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>It is now possible to seamlessly pass around a <code class="language-plaintext highlighter-rouge">dyn DataRootDyn</code> and use it as if it were a regular <code class="language-plaintext highlighter-rouge">DataRoot</code>:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nf">FauxUser</span><span class="p">(</span><span class="nb">u64</span><span class="p">);</span>

<span class="k">impl</span> <span class="n">User</span> <span class="k">for</span> <span class="n">FauxUser</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">id</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">u64</span> <span class="p">{</span>
        <span class="k">self</span><span class="na">.0</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">struct</span> <span class="n">FauxDataRoot</span><span class="p">;</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="nv">'l</span><span class="o">&gt;</span> <span class="n">DataRoot</span><span class="o">&lt;</span><span class="nv">'l</span><span class="o">&gt;</span> <span class="k">for</span> <span class="n">FauxDataRoot</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">get_user</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">id</span><span class="p">:</span> <span class="nb">u64</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">impl</span> <span class="n">User</span> <span class="o">+</span> <span class="nv">'l</span> <span class="p">{</span>
        <span class="nf">FauxUser</span><span class="p">(</span><span class="n">id</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="n">use_data_root</span><span class="o">&lt;</span><span class="nv">'l</span><span class="o">&gt;</span><span class="p">(</span><span class="n">root</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'l</span> <span class="k">mut</span> <span class="k">dyn</span> <span class="n">DataRootDyn</span><span class="o">&lt;</span><span class="nv">'l</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">{</span>
    <span class="nd">println!</span><span class="p">(</span><span class="s">"{}"</span><span class="p">,</span> <span class="n">root</span><span class="nf">.get_user</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span><span class="nf">.id</span><span class="p">());</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">root</span> <span class="o">=</span> <span class="n">FauxDataRoot</span><span class="p">;</span>
    <span class="nf">use_data_root</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">root</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>]]></content><author><name></name></author><category term="software" /><summary type="html"><![CDATA[Not all Rust traits can be used as dynamic trait objects, but that doesn't have to limit what you can do dynamically.]]></summary></entry><entry><title type="html">Green Thread Overhead - Async in a Trench Coat</title><link href="https://scp-iota.github.io/software/2025/09/14/green-thread-overhead.html" rel="alternate" type="text/html" title="Green Thread Overhead - Async in a Trench Coat" /><published>2025-09-14T00:00:00+00:00</published><updated>2025-09-14T00:00:00+00:00</updated><id>https://scp-iota.github.io/software/2025/09/14/green-thread-overhead</id><content type="html" xml:base="https://scp-iota.github.io/software/2025/09/14/green-thread-overhead.html"><![CDATA[<p>So, you just finished writing your handy higher-order utility function that does that one type of thing that pops up all over your codebase, and now you’re ready to streamline everything. Only, there’s a problem: some of the places you intend to use it require asynchronous operations, and now you have to choose between making your utility asynchronous, which will prevent it from being used in synchronous code, or avoiding using it for asynchronous tasks. You settle for creating a separate asynchronous version of the function, and for a brief moment, you feel like this dilemma is a synthetic limitation, and wonder if it could be solved if the language could “just let you call asynchronous functions synchronously.” Then, you come to your senses. Almost.</p>

<h2 id="why-async">Why <code class="language-plaintext highlighter-rouge">async</code>?</h2>

<p>Let’s start by thinking about why we have <code class="language-plaintext highlighter-rouge">async</code> functions to begin with; what problem do they solve? The gist is that many kinds of operations, especially I/O, involve waiting until an external task has finished. During that time, other code could be running until the result is ready. That is what asynchronous code makes possible: “pausing” the flow of code in one task to allow other tasks to run, by internally breaking functions into separate chunks.</p>

<p>Consider, for example, the following asynchronous JavaScript function:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">async</span> <span class="kd">function</span> <span class="nf">getUsername</span><span class="p">()</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="k">await</span> <span class="nf">fetch</span><span class="p">(</span><span class="dl">'</span><span class="s1">/api/session</span><span class="dl">'</span><span class="p">)</span>
    <span class="kd">const</span> <span class="nx">json</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">response</span><span class="p">.</span><span class="nf">json</span><span class="p">()</span>
    <span class="k">return</span> <span class="nx">json</span><span class="p">.</span><span class="nx">username</span>
<span class="p">}</span>
</code></pre></div></div>

<p>It is functionally equivalent to this code, which does not use <code class="language-plaintext highlighter-rouge">async</code>:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">getUsername</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">return</span> <span class="k">new</span> <span class="nc">Promise</span><span class="p">((</span><span class="nx">resolve</span><span class="p">,</span> <span class="nx">reject</span><span class="p">)</span> <span class="o">=&gt;</span>
        <span class="nf">fetch</span><span class="p">(</span><span class="dl">'</span><span class="s1">/api/session</span><span class="dl">'</span><span class="p">)</span>
            <span class="p">.</span><span class="nf">then</span><span class="p">(</span><span class="nx">response</span> <span class="o">=&gt;</span>
                <span class="nx">response</span><span class="p">.</span><span class="nf">json</span><span class="p">()</span>
                    <span class="p">.</span><span class="nf">then</span><span class="p">(</span><span class="nx">json</span> <span class="o">=&gt;</span> <span class="nf">resolve</span><span class="p">(</span><span class="nx">json</span><span class="p">.</span><span class="nx">username</span><span class="p">))</span>
                    <span class="p">.</span><span class="k">catch</span><span class="p">(</span><span class="nx">reject</span><span class="p">)</span>
            <span class="p">)</span>
            <span class="p">.</span><span class="k">catch</span><span class="p">(</span><span class="nx">reject</span><span class="p">)</span>
    <span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Clearly, the former code is cleaner, and that is why the syntax sugar provided by <code class="language-plaintext highlighter-rouge">async</code> exists: to simplify working with tasks that cannot finish in a single flow of execution.</p>

<h2 id="why-not-synchronous">Why Not Synchronous</h2>

<p>This is where many people start to lose track of the point; the illusion of continuity created by the <code class="language-plaintext highlighter-rouge">async</code> syntax sugar leads some to forget the underlying mechanics and believe that the inability to call an asynchronous function from within a synchronous one is an artificial restriction.</p>

<p>“Why can’t I do this?…”</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">getUserProfileURL</span><span class="p">()</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">username</span> <span class="o">=</span> <span class="nf">getUsername</span><span class="p">();</span>
    <span class="k">return</span> <span class="nx">siteRoot</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">/users/</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">username</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This textbook answer is that such code is incorrect because <code class="language-plaintext highlighter-rouge">getUsername</code> is an asynchronous function, and therefore cannot be called from <code class="language-plaintext highlighter-rouge">getUserProfileURL</code>, which is synchronous. But let’s consider <em>why</em>: <code class="language-plaintext highlighter-rouge">getUsername</code> is asynchronous because it relies on an inherently asynchronous operation (a network request, which is in turn asynchronous because it must wait for I/O and a response.) Because of that, <code class="language-plaintext highlighter-rouge">getUsername</code> isn’t so much a function that “gets the username” as it is a function that “<em>schedules the task of getting the username</em>.” It <em>has</em> to be this way because there is no way to force the result to arrive immediately; the requester has to wait.</p>

<p>With that in mind, it becomes clear why a synchronous function like <code class="language-plaintext highlighter-rouge">getUserProfileURL</code> cannot call <code class="language-plaintext highlighter-rouge">getUsername</code>: <code class="language-plaintext highlighter-rouge">getUserProfileURL</code> does not “schedule a task,” but rather is expected to do something and return a result immediately. It can’t do that if it first has to wait on a sub-operation to finish externally.</p>

<h2 id="green-threads">“Green Threads”</h2>

<p>Some people point to languages that support green threads, such as Go, Dart, and (some versions of) Java, as evidence that it could be possible to design a language that allows calling an asynchronous operation from within a synchronous context.</p>

<p>Green-threaded languages work by fundamentally changing the way function execution happens; instead of a single program stack, a function’s stack frame exists on one of several “green thread stacks,” which are allocated by the execution environment that manages the green threads. Certain operations (for example, any I/O in Go) internally have an extra step at the end that gives the execution environment a chance to switch the active green thread if needed. A certain routine of the execution environment will be invoked that may determine that it’s a good time to switch to a different green thread, and if it does, it will <em>store the address of program execution into a place associated with the current green thread and then jump to the previously stored program execution address of a different one.</em> This simulates “pausing” the current green thread and “resuming” another. Since the green threads have separate stacks, there is no interference from executing other code while one green thread is paused. This seems oddly familiar, though.</p>

<h2 id="async-with-extra-steps"><code class="language-plaintext highlighter-rouge">async</code> With Extra Steps</h2>

<p>The above method of wrangling green threads is functionally equivalent to making every function <code class="language-plaintext highlighter-rouge">async</code>. Like the separate stacks, variables in <code class="language-plaintext highlighter-rouge">async</code> functions become properties of the internal state objects that get passed between executions of asynchronous tasks. Like the specific operations that trigger a chance to switch green threads, <code class="language-plaintext highlighter-rouge">async</code> functions use <code class="language-plaintext highlighter-rouge">await</code> as an indicator to yield continuity until the result is ready. And like storing execution addresses, registering callback functions provides a way for the environment to know what to call to resume execution of the task. Green threads aren’t so much “threads” as they are the result of hiding asynchronicity behind <em>another</em> layer of syntax sugar: the language itself. That comes with a cost, too.</p>

<h2 id="static-analysis-security-and-platform-support">Static Analysis, Security, and Platform Support</h2>

<p>If you were to try to manually implement the kind of internal coordination done with green threads, you would likely run into a problem: it relies on arbitrary jumps. Of course, many languages support the use of jumps <em>within a function</em>, jumping to an arbitrary address in a different function is usually unsupported for a lot of reasons. One of those reasons is that static analysis algorithms, like those used in optimizers, security software, and even in your CPU itself to maximize the benefit of caching, rely on jump instructions only occurring in certain kinds of well-known patterns. For example, conditional blocks and loops can be detected from the way jump instructions are positioned relative to their target address.</p>

<p>If, however, an arbitrary jump instruction is found, it may become impossible for static analysis algorithms to understand the logic of the code. Even worse, the existence of <em>even one</em> arbitrary jump <em>anywhere in the code</em> can be enough to prevent some kinds of optimization and security guarantees even if there is no logical reason why the jump would interfere, simply because the algorithm can no longer be certain that the jump wouldn’t send the execution flow to a position in the code that it could otherwise guarantee would only be accessed under specific conditions.</p>

<p>This problem also has a more concrete consequence than just disabling some optimizations: certain target architectures, notably WebAssembly, do not allow arbitrary jump instructions at all because they prevent static guarantees about the state of the stack. Since all WebAssembly functions are expressed in terms of values on the stack, while the compiled machine code usually maps these stack values into registers, the layout of the stack must be statically known and guaranteed. If it were possible to arbitrarily jump around in the code, unexpected code paths could unbalance the stack from its expected layout and cause fatal errors. Such code flow could even be used maliciously to break out of the sandbox. Since arbitrary jumps are not an option for these targets, languages that support green threads have to find workarounds. Often, the result is less efficient than using asynchronous functions.</p>

<h2 id="what-standard-library">What Standard Library?</h2>

<p>Then there’s the issue of ensuring that those task-switching operations are called regularly or at key points. As mentioned, Go ensures that the execution environment gets a chance to switch green threads at every I/O operation, but that first requires a standard library where all I/O operations are provided with a call to that procedure. Which, of course, first requires a <em>standard library</em>. That’s a problem for, say, embedded systems, where code is often compiled with only a minimal core library, and operations like I/O come from elsewhere.</p>

<h2 id="but-thats-none-of-my-business">But That’s None of My Business</h2>

<p>That said, most of these concerns are related to statically compiled languages. One wouldn’t expect to use static analysis on the JIT-compiled machine instructions of a Java program when the bytecode is already known. Nor would one expect to run their Go code on an embedded chip in their coffee maker. (Well, <em>maybe</em> not.) But it still seems important to consider the caveats to different execution models and how that could affect what environments they may or may not be ideal for.</p>]]></content><author><name></name></author><category term="software" /><summary type="html"><![CDATA[How do green threads work, and how do they compare to async functions?]]></summary></entry><entry><title type="html">What Have We Become? - A Portmortem of Pride 2025</title><link href="https://scp-iota.github.io/queer_stuff/2025/07/02/what-have-we-become.html" rel="alternate" type="text/html" title="What Have We Become? - A Portmortem of Pride 2025" /><published>2025-07-02T00:00:00+00:00</published><updated>2025-07-02T00:00:00+00:00</updated><id>https://scp-iota.github.io/queer_stuff/2025/07/02/what-have-we-become</id><content type="html" xml:base="https://scp-iota.github.io/queer_stuff/2025/07/02/what-have-we-become.html"><![CDATA[<blockquote>
  <p>“Way up way up we go</p>

  <p>Been up and down that road</p>

  <p>Way up way up, oh no</p>

  <p>We gon’ burn the whole house down”</p>

  <ul>
    <li>AJR, Burn the House Down</li>
  </ul>
</blockquote>

<p>Last month marks the fifty-sixth anniversary of the Stonewall Riots - the day that Manhattan police raided the Stonewall Inn, one of the few places in New York City where openly queer people were allowed at the time. Subjected to inspections, arrests, and brutality, the crowd of gay patrons finally decided they’d had enough; for six days, they fought back against the raid as others joined from nearby and the mob grew. Once the now-iconic crossfire of bricks ceased and the dust settled, with riot control forces left trapped inside the building, a new era of queer activism began.</p>

<p>Organizations like the Gay Liberation Front formed to take a more public approach to the fight, and a sentiment of uncompromising rebellion spread through gay communities. We have these events and people to thank for modern queer rights, but we must now ask ourselves, have we lost the spirit? In this new age of increased acceptance and inclusion, have we become complacent with the oppression that remains and subdued once more by an attitude of compliance? More importantly, now that we live in a time when we can be openly queer without the imminent risk of police raids, has the fundamental meaning of being queer changed for the worse?</p>

<p>As bad as things still are, at least far fewer of us are at risk of homelessness, violence, and legal issues (for now). The hidden cost of society’s increased acceptence towards queer people, however, is that more and more of the queer community has skipped an important step: losing faith in society’s normative ideas. Don’t get me wrong - the progress we have seen is amazing and worth every bit of the fighting it takes to achieve - but what was once the most basic part of the queer movement is leaving us. Now, many queer people still retain a level of faith in normativity of gender roles and society’s structures, and rather than “cutting out the core” of these ideas, they merely select queer culture <em>as an aspect of</em> societal structure.</p>

<p>Back when being openly queer could lead to exclusion and possibly punishment, the strain between one’s own identity and the way society viewed it forced a choice: either repress oneself or reject normative society - there was no middle ground. Many modern queer people still think this way, but the assimilationist concessions we are now afforded have led many others to sidestep that crucial faith-breaking moment. Two major effects have come from this phenomenon: queer infighting and strengthened conservative arguments.</p>

<p>Within our own communities, there has been an increase in “border wars” between different types of queer identity who latch onto some normative ideas as a way to justify their rejection of other ideas without a need to reject the core concept of normativity. For example, we sometimes see binary trans people reinforcing a binary notion of gender and fighting against non-binary people because those binary trans people have constructed their view of being trans around the binary. We also see gay and lesbian people attempting to exclude bi and pan people because, although they have rejected heteronormativity, they have not yet rejected the idea that orientation need not be strictly tied to one gender. Biphobic arguments often also inadvertently reinforce gender roles. It is also common for even more widely accepting queer communitied to exclude asexual people because they have defined themsevles in terms of their specific labels rather than in terms of being outside of cisheteronormativity.</p>

<p>With this movement of queer culture from being outside of normative society to being a different part of it comes a new argument from conservative opposition: that we are no different from them because we are just yet another culture in the pot. Unfortunately, if we continue this trend of keeping some level of faith in normativity, they are not entirely wrong here; parts of the queer community <em>have</em> become “just another slice of society.” If we want to come back from this and avoid being “no different from them,” we need to return to our outright rejection of the core concept of normativity.</p>

<p>I don’t say any of this to discredit how far we’ve come or the change we have achieved, but rather to warn of where we may end up if we go too far into assimilation. I understand that assimilation can be a useful tool for progress, but we must remember that it is just that: a <em>means to an end</em>, not an idea that we should define ourselves in terms of. Being queer under normativity is a losing game, so let’s remind ourselves not to turn that tool into a weapon against each other.</p>]]></content><author><name></name></author><category term="queer_stuff" /><summary type="html"><![CDATA[“Way up way up we go Been up and down that road Way up way up, oh no We gon’ burn the whole house down” AJR, Burn the House Down]]></summary></entry><entry><title type="html">How to Actually Download More RAM - Google Drive as Linux Swap Space</title><link href="https://scp-iota.github.io/software/2025/06/16/download-ram-swap-gdrive.html" rel="alternate" type="text/html" title="How to Actually Download More RAM - Google Drive as Linux Swap Space" /><published>2025-06-16T00:00:00+00:00</published><updated>2025-06-16T00:00:00+00:00</updated><id>https://scp-iota.github.io/software/2025/06/16/download-ram-swap-gdrive</id><content type="html" xml:base="https://scp-iota.github.io/software/2025/06/16/download-ram-swap-gdrive.html"><![CDATA[<p>We’ve all seen the jokes. “I can’t play that game anymore because the update needs too much RAM.” “Just download more lol.” For those without ad blockers, promises of “free downloadable RAM” plague the Internet with false hope and countless strains of malware. Obviously it’s impossible for real, physical RAM - the kind that has a direct line to your CPU - but you might not have known that it’s possible to expand the software-level maximum memory capacity of your system with an online service. Before you get your hopes up, I must warn you - it’s nowhere near efficient and probably not even worth doing. However, I’m not here to do things worth doing; I’m here to do what they said couldn’t be done.</p>

<h2 id="what-sorcery-is-this">“What sorcery is this?”</h2>

<p>Most operating systems have a backup plan for when your physical RAM supply runs out: <em>swap space</em>. Unlike real RAM, this overflow space cannot be directly accessed by programs that are actively using memory; instead, when more memory is needed than can be allocated, pages of memory that haven’t been used as recently are “swapped” out of physical RAM and stored in the swap space to allow that section of physical memory to be repurposed for the new demand. When a program tries to access the memory that was swapped out, the operating system will swap it back into physical RAM, which might require swapping out a different page. Typically, this extra space is provided by a portion of your hard drive space, since that’s the second most accesible kind of memory your system has access to, but as we’ll see, it doesn’t have to be. Compared to ideal conditions of sufficient physical RAM, all this swapping can severly reduce efficiency, especially if programs need quick access to various pieces of data scattered around the memory address space, but at least it <em>works</em>, and that’s more than can be said about <code class="language-plaintext highlighter-rouge">fatal error: runtime: out of memory</code></p>

<h2 id="loop-the-loop">Loop the loop</h2>

<p>On Linux, swap space is a dedicated type of partition separate from filesystems. For example, you might have a partition <code class="language-plaintext highlighter-rouge">/dev/sda3</code> that’s formatted as a swap partition and configured to be your system’s swap provider. In that case, <code class="language-plaintext highlighter-rouge">/dev/sda3</code> is a <em>block device</em> that the Linux kernel can read and write. You can create block devices out of anything, though - including regular files - using <em>loopback devices</em>. A loopback devices is a block device node that proxies read and write operations to a different path, which can be another device, a regular file, or a file provided by a virtual filesystem. To “download some RAM,” we’ll use the latter to put a swap partition on a file in cloud storage.</p>

<h2 id="setup">Setup</h2>

<h3 id="1-virtual-filesystem-for-google-drive">1. Virtual Filesystem for Google Drive</h3>

<p>This can be done with any cloud storage provider, but this guide will use Google Drive for the example. <strong>I will warn that using cloud storage as swap space risks leaking sensitive data like passwords into the cloud. This is really just a silly guide for the lulz. Only do this at your own risk.</strong></p>

<p>To use Google Drive as a local filesystem, we need a virtual filesystem implementation for that. This guide will use <a href="https://github.com/astrada/google-drive-ocamlfuse"><code class="language-plaintext highlighter-rouge">google-drive-ocamlfuse</code></a>, which has an installation guide <a href="https://github.com/astrada/google-drive-ocamlfuse/wiki/Installation">here</a>. For this guide, I have mounted my Google Drive into <code class="language-plaintext highlighter-rouge">~/GoogleDrive</code>.</p>

<p>It is important for the root user to have access to the filesystem. This is not the default for FUSE-based filesystems, so you’ll need to uncomment the <code class="language-plaintext highlighter-rouge">user_allow_other</code> line in <code class="language-plaintext highlighter-rouge">/etc/fuse.conf</code> and add the <code class="language-plaintext highlighter-rouge">allow_root</code> option when mounting. For me, the command was:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>google-drive-ocamlfuse <span class="nt">-o</span><span class="o">=</span>allow_root ~/GoogleDrive/
</code></pre></div></div>

<h3 id="2-create-a-swap-space-file-and-loopback-device">2. Create a Swap Space File and Loopback Device</h3>

<p>To reserve space for swap, we need to create a file filled with the intended number of bytes. This example will allocate a gigabyte of swap.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">dd </span><span class="nv">bs</span><span class="o">=</span>1024 <span class="nv">count</span><span class="o">=</span>1048576 <span class="k">if</span><span class="o">=</span>/dev/zero <span class="nv">of</span><span class="o">=</span>~/GoogleDrive/swap
</code></pre></div></div>

<p>This command won’t necessarily end automatically when the bytes have all been written, so you’ll need to keep an eye on the file size to see when it is done. Use the file size shown by the virtual filesystem, not Google Drive’s online details, since they may not synchronize immediately.</p>

<p>Now we need to create a loopback device that points to this file:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>losetup <span class="nt">-f</span> <span class="nt">--show</span> ~/GoogleDrive/swap
</code></pre></div></div>

<p>This command will output the path to the new loop device. For me, that was <code class="language-plaintext highlighter-rouge">/dev/loop0</code>, but it may be different for you. I’ll store it in a variable and use only the variable to refer to it for now. The next step is formatting the content of the file as a swap partition:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">SWAP_LOOP</span><span class="o">=</span>/dev/loop0
<span class="nb">sudo </span>mkswap <span class="s2">"</span><span class="nv">$SWAP_LOOP</span><span class="s2">"</span>
</code></pre></div></div>

<h2 id="and-were-up">And We’re Up!</h2>

<p>Finally, we’re ready to tell the Linux kernel to use the loop device as swap space:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>swapon <span class="s2">"</span><span class="nv">$SWAP_LOOP</span><span class="s2">"</span>
</code></pre></div></div>

<h2 id="cleaning-up">Cleaning Up</h2>

<p>When you’re done using your terribly inefficient free downloadable RAM, you can stop using it as swap, remove the loop device, and unmount the virtual filesystem:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>swapoff <span class="s2">"</span><span class="nv">$SWAP_LOOP</span><span class="s2">"</span>
<span class="nb">sudo </span>losetup <span class="nt">-d</span> <span class="s2">"</span><span class="nv">$SWAP_LOOP</span><span class="s2">"</span>
fusermount <span class="nt">-u</span> ~/GoogleDrive
</code></pre></div></div>

<h2 id="now-go-forth-and-engage-the-trolls">Now Go Forth, and Engage the Trolls</h2>

<p>With the knowledge in this guide, you are now ready to drop a link to this as a sarcastic response to all the bait and overused jokes about “downloading more RAM” you encounter during your online wanderings.</p>]]></content><author><name></name></author><category term="software" /><summary type="html"><![CDATA[What if you really could "download more RAM?" Linux allows any block device to be swap space, so maybe you can...]]></summary></entry><entry><title type="html">Rust Could be a Good Beginner Language</title><link href="https://scp-iota.github.io/software/2025/06/11/rust-for-beginners.html" rel="alternate" type="text/html" title="Rust Could be a Good Beginner Language" /><published>2025-06-11T00:00:00+00:00</published><updated>2025-06-11T00:00:00+00:00</updated><id>https://scp-iota.github.io/software/2025/06/11/rust-for-beginners</id><content type="html" xml:base="https://scp-iota.github.io/software/2025/06/11/rust-for-beginners.html"><![CDATA[<p>If I had a nickel for every question along the lines of “What programming language should I learn as a beginner?” posted online, I’d pay for these people’s Rust courses. I know it sounds counterintuitive; after all, Rust is the new C++, not the new Python, right? Yet, when I stop and think about which aspects of Rust made it difficult to get used to, it wasn’t the usual stumbling blocks of low-level languages. That’s not just because I already knew C++, either; rather, it felt like Rust actually <em>eased</em> many of those pitfalls, while the parts that tripped me up did so because they felt entirely new and incomparable to the languages I had already learned. The turning point that made it suddenly easier to understand Rust was when I realized that I needed to stop trying to map concepts from other languages into Rust syntax and start learning Rust <em>as a system</em> rather than merely <em>as a language</em>.</p>

<p>A beginner learning their first programming language, on the other hand, is not already familiar with the ways of thinking that we tend to hold in our minds when we set out to add another language to our collection. These newbies are tasked with learning the concepts and the language simultaneously, and, despite the difficulty that <em>adds</em>, that process can also <em>ease</em> learning when the language relies on concepts that differ from those the rest of us have already learned.</p>

<p>Rust, for all the talk of its high-and-mighty enlightenment that mere mortals have too much “skill issue” to comprehend, might be an ideal language for absolute beginners to learn programming concepts in a way that better helps them eventually understand computing and move on to other languages.</p>

<h2 id="forget-everything-you-know">“Forget Everything You Know”</h2>

<p>Imagine a beginner to programming - let’s call him Kevin. Kevin has just finished learning about structures or classes, depending on which language he is learning, and now wants to try passing an instance to a function. If he was learning, say, Python, he might try something like this:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Person</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">age</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
        <span class="n">self</span><span class="p">.</span><span class="n">age</span> <span class="o">=</span> <span class="n">age</span>

<span class="k">def</span> <span class="nf">increase_age</span><span class="p">(</span><span class="n">person</span><span class="p">):</span>
    <span class="n">person</span><span class="p">.</span><span class="n">age</span> <span class="o">+=</span> <span class="mi">1</span>
    <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="si">{</span><span class="n">person</span><span class="p">.</span><span class="n">name</span><span class="si">}</span><span class="s"> has aged</span><span class="sh">'</span><span class="p">)</span>

<span class="n">ada</span> <span class="o">=</span> <span class="nc">Person</span><span class="p">(</span><span class="sh">'</span><span class="s">Ada Lovelace</span><span class="sh">'</span><span class="p">,</span> <span class="mi">35</span><span class="p">)</span>
<span class="nf">increase_age</span><span class="p">(</span><span class="n">ada</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="s">new age: </span><span class="si">{</span><span class="n">ada</span><span class="p">.</span><span class="n">age</span><span class="si">}</span><span class="sh">'</span><span class="p">)</span>
</code></pre></div></div>

<p>Kevin has just figured out that objects in Python are passed by reference - when he changes a property of an object that came from a parameter, it changes the same object that was created by the caller. This can be just as much of a pitfall as a feature for a beginner:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">olympics_2010_ice_dancing_placed_nations</span> <span class="o">=</span> <span class="p">[</span><span class="sh">'</span><span class="s">United States</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">Russia</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">Canada</span><span class="sh">'</span><span class="p">]</span>
<span class="n">olympics_2010_ice_dancing_nation_points</span> <span class="o">=</span> <span class="p">[</span><span class="mf">215.74</span><span class="p">,</span> <span class="mf">207.64</span><span class="p">,</span> <span class="mf">221.57</span><span class="p">]</span>

<span class="k">def</span> <span class="nf">display_nations</span><span class="p">(</span><span class="n">nations</span><span class="p">):</span>
    <span class="n">nations</span><span class="p">.</span><span class="nf">sort</span><span class="p">()</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">'</span><span class="s">Nations that placed:</span><span class="sh">'</span><span class="p">)</span>

    <span class="k">for</span> <span class="n">nation</span> <span class="ow">in</span> <span class="n">nations</span><span class="p">:</span>
        <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="s">* </span><span class="si">{</span><span class="n">nation</span><span class="si">}</span><span class="sh">'</span><span class="p">)</span>

<span class="nf">display_nations</span><span class="p">(</span><span class="n">olympics_2010_ice_dancing_placed_nations</span><span class="p">)</span>
<span class="n">canada_index</span> <span class="o">=</span> <span class="n">olympics_2010_ice_dancing_placed_nations</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="sh">'</span><span class="s">Canada</span><span class="sh">'</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="s">Canada scored a total of </span><span class="si">{</span><span class="n">olympics_2010_ice_dancing_nation_points</span><span class="p">[</span><span class="n">canada_index</span><span class="p">]</span><span class="si">}</span><span class="s"> points</span><span class="sh">'</span><span class="p">)</span>
</code></pre></div></div>

<p>Yes, I know it’s messy, but it’s messy in the way an inexperienced programmer’s code might be. There’s a bigger problem here: according to the output of this program, <code class="language-plaintext highlighter-rouge">Canada scored a total of 215.74 points</code>, but that is incorrect - Canada scored 221.57 points as shown in the lists.</p>

<p>The issue is that the <code class="language-plaintext highlighter-rouge">.sort()</code> changes the list of nations <em>in-place</em>, which takes it out of alignment with the score list. This could’ve been avoided using <code class="language-plaintext highlighter-rouge">.sorted()</code>, but a beginner might not think about how the changes they make to a list from a parameter could affect other code because, the way they might see it, the parameter falls out of scope right after and it doesn’t matter.</p>

<p>Now consider an alternate universe where our hypothermic Kevin is instead learning Rust. That same program might look like this:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">display_nations</span><span class="p">(</span><span class="k">mut</span> <span class="n">nations</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;&amp;</span><span class="nb">str</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">nations</span><span class="nf">.sort</span><span class="p">();</span>
    <span class="nd">println!</span><span class="p">(</span><span class="s">"Nations that placed:"</span><span class="p">);</span>
    
    <span class="k">for</span> <span class="n">nation</span> <span class="k">in</span> <span class="n">nations</span> <span class="p">{</span>
        <span class="nd">println!</span><span class="p">(</span><span class="s">"* {}"</span><span class="p">,</span> <span class="n">nation</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">olympics_2010_ice_dancing_placed_nations</span> <span class="o">=</span> <span class="nd">vec!</span><span class="p">[</span><span class="s">"United States"</span><span class="p">,</span> <span class="s">"Russia"</span><span class="p">,</span> <span class="s">"Canada"</span><span class="p">];</span>
    <span class="k">let</span> <span class="n">olympics_2010_ice_dancing_nation_points</span> <span class="o">=</span> <span class="p">[</span><span class="mf">215.74</span><span class="p">,</span> <span class="mf">207.64</span><span class="p">,</span> <span class="mf">221.57</span><span class="p">];</span>
    
    <span class="nf">display_nations</span><span class="p">(</span><span class="n">olympics_2010_ice_dancing_placed_nations</span><span class="nf">.clone</span><span class="p">());</span>
    <span class="k">let</span> <span class="n">canada_index</span> <span class="o">=</span> <span class="n">olympics_2010_ice_dancing_placed_nations</span><span class="nf">.iter</span><span class="p">()</span><span class="nf">.position</span><span class="p">(|</span><span class="o">&amp;</span><span class="n">n</span><span class="p">|</span> <span class="n">n</span> <span class="o">==</span> <span class="s">"Canada"</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="nd">println!</span><span class="p">(</span><span class="s">"Canada scored a total of {} points"</span><span class="p">,</span> <span class="n">olympics_2010_ice_dancing_nation_points</span><span class="p">[</span><span class="n">canada_index</span><span class="p">]);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Grumbles about using <code class="language-plaintext highlighter-rouge">Vec&lt;&amp;str&gt;</code> instead of <code class="language-plaintext highlighter-rouge">Vec&lt;impl AsRef&lt;str&gt; + Ord + Display&gt;</code> aside, I can hear the angry readers already: “That’s cheating! You snuck a <code class="language-plaintext highlighter-rouge">.clone()</code> in there to fix the issue!” The thing is, though, <em>Rust’s borrow checker made me put that there.</em> Without the <code class="language-plaintext highlighter-rouge">.clone()</code>, the compiler would complain about the line that determines <code class="language-plaintext highlighter-rouge">canada_index</code> because the array of nations has already been moved by that point. If the beginner had instead fixed that by making <code class="language-plaintext highlighter-rouge">display_nations</code> take a reference rather than taking the vector by value, the compiler would’ve complained that the array cannot be borrowed as mutable because it is not declared as mutable, and with that, the programmer would become aware that there is a risk of changing something that needs to stay in the same order.</p>

<p>The point is that Rust’s concepts of reference vs. value passing, ownership, and immutability make the programmer aware of things that would remain in the background in a language like Python, and that’s especially bad for beginners who might not think of those things and shoot themselves in the foot.</p>

<p>This raises the question of whether learning about things like ownership and references makes Rust too hard to learn as a first language - and I think the answer is no. Ownership may trip up programmers with experience in other languages who move on to learning Rust, but a beginner learning Rust first would learn it as a basic concept just like any other. In a way, the idea of value ownership is a very tangible and intuitive part of Rust that I think many beginners will have no issue visualizing. It’s the ones of us who think we already have the concepts we need that become confused.</p>

<h2 id="too-verbose">Too Verbose?</h2>

<p>There is a reason Python is a popular first language, and it’s not just because of the machine learning boom. As a dynamic language, Python is semantically simple with its lack of type declarations. Compared to learning, say, Java as a first language, Python keeps that part out of the visual space so that the programmer can focus on the flow of the program. As we’ve seen from complaints about runtime errors, though, a dynamic type system can create pitfalls of its own. A nice middle ground is type inference, which has the simplicity benefits of no explicit type declarations at the same time as compile-time type checking. This can be seen with the likes of C# and Kotlin, and modern Java’s <code class="language-plaintext highlighter-rouge">var</code> and C++’s <code class="language-plaintext highlighter-rouge">auto</code>, but these basic type inference solutions that were shoehorned into existing languages are only useful in some situations and leave quite a bit of code still requiring explicit types. Rust, however, has powerful type inference. Take for example this simple Rust program:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">io</span><span class="p">::{</span><span class="n">stdin</span><span class="p">,</span> <span class="n">stdout</span><span class="p">,</span> <span class="n">Write</span><span class="p">};</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">input</span> <span class="o">=</span> <span class="nf">stdin</span><span class="p">();</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">output</span> <span class="o">=</span> <span class="nf">stdout</span><span class="p">();</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">numbers</span> <span class="o">=</span> <span class="nd">vec!</span><span class="p">[];</span>
    
    <span class="nd">println!</span><span class="p">(</span><span class="s">"Enter some numbers, one per line. Leave blank to stop:"</span><span class="p">);</span>
    
    <span class="k">loop</span> <span class="p">{</span>
        <span class="nd">print!</span><span class="p">(</span><span class="s">"-&gt; "</span><span class="p">);</span>
        <span class="n">output</span><span class="nf">.flush</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
        <span class="k">let</span> <span class="k">mut</span> <span class="n">line</span> <span class="o">=</span> <span class="nn">String</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
        <span class="n">input</span><span class="nf">.read_line</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">line</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">();</span>
        <span class="k">let</span> <span class="n">value</span> <span class="o">=</span> <span class="n">line</span><span class="nf">.trim</span><span class="p">();</span>
        
        <span class="k">if</span> <span class="n">value</span><span class="nf">.is_empty</span><span class="p">()</span> <span class="p">{</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span>
        
        <span class="k">if</span> <span class="k">let</span> <span class="nf">Ok</span><span class="p">(</span><span class="n">num</span><span class="p">)</span> <span class="o">=</span> <span class="n">value</span><span class="py">.parse</span><span class="p">::</span><span class="o">&lt;</span><span class="nb">f32</span><span class="o">&gt;</span><span class="p">()</span> <span class="p">{</span>
            <span class="n">numbers</span><span class="nf">.push</span><span class="p">(</span><span class="n">num</span><span class="p">);</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="nd">println!</span><span class="p">(</span><span class="s">"That's not a valid number."</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
    
    <span class="nd">println!</span><span class="p">(</span><span class="s">"Sum of all numbers: {}"</span><span class="p">,</span> <span class="n">numbers</span><span class="nf">.iter</span><span class="p">()</span><span class="py">.sum</span><span class="p">::</span><span class="o">&lt;</span><span class="nb">f32</span><span class="o">&gt;</span><span class="p">());</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Notice how there are only two explicit type annotations in all this - the ones for <code class="language-plaintext highlighter-rouge">parse</code> and <code class="language-plaintext highlighter-rouge">sum</code>. All of the variables have inferred types. Notably, even the vector has an inferred item type, which Rust detects from the code later on. This larger scope for type inference compared to most languages allows code to <em>look</em> more like the simple, dynamically typed Python despite benefitting from compile-time type checks.</p>

<h2 id="a-solid-foundation">A Solid Foundation</h2>

<p>Many of us started learning programming with simpler languages like Python and then worked up to the likes of C++, and many of us remember the difficulties of getting used to lower-level concepts we had never seen before. If a beginner started with Rust and learned the basics of programming while being exposed to concepts like ownership, moving, and references, even if they had no understanding of the underlying memory it would likely be easier for them to learn C++. Learning Rust builds a foundation that may prepare someone to learn a difficult low-level language even if they do not learn those advanced concepts in Rust itself. We as people who learned Rust after other languages are facing the difficulties of a top-down learning order, so let’s prepare the next set of programmers to go from the bottom up.</p>]]></content><author><name></name></author><category term="software" /><summary type="html"><![CDATA[It's often assumed that Rust's low-level nature and fundamental differences from common languages make it unsuitable for beginners, but I suggest that Rust's apparent difficulty is instead caused by our familiarity with other languages.]]></summary></entry><entry><title type="html">Google brags to other companies about their permanent rainbow logo this Pride Month</title><link href="https://scp-iota.github.io/satire/2025/06/02/google-brags-pride-logo.html" rel="alternate" type="text/html" title="Google brags to other companies about their permanent rainbow logo this Pride Month" /><published>2025-06-02T00:00:00+00:00</published><updated>2025-06-02T00:00:00+00:00</updated><id>https://scp-iota.github.io/satire/2025/06/02/google-brags-pride-logo</id><content type="html" xml:base="https://scp-iota.github.io/satire/2025/06/02/google-brags-pride-logo.html"><![CDATA[<p>Each June, numerous companies temporarily change their logo to a rainbow-colored variant for Pride Month. One major exception to this seasonal change is Google; rather than deal with the hassle of annual temporary rebrands, this company has kept their chromatic logo year-round for ages. This year, they’ve decided to rub it in other big tech companies’ faces.</p>

<blockquote>
  <p>“Those other corporations don’t have the level of commitment we do. While they are only willing to let the full spectrum of colors on their logos burn in their eyes for a month at most, we’ve had the rainbow since 2009.”</p>
</blockquote>

<p>Their head of marketing made specific mention of one of their, arguably, rivals: Apple.</p>

<blockquote>
  <p>“Now, I know we’re not the only tech company to have had a rainbow logo year-round; Apple had one for over a decade, but even they chickened out. It was too much for them, I guess - the cone cells in their eyes just couldn’t take it.”</p>
</blockquote>

<p>The attentive reader might notice that the subject of logo changes has recently resurfaced at Google - just this year, the tech giant changed their main app logo from the long-standing letter ‘G’ with banded colors to the same letter with a continuous color spectrum.</p>

<blockquote>
  <p>“At Google, we’re not only holding out, but upping our game: in an effort to increase inclusion, we’ve changed our logo to include every visible color - not just a few primaries. Well, given enough pixels, that is.”</p>
</blockquote>

<p>When asked about what other changes and actions the corporation would be doing in regards to Pride Month, the marketing head paused for a second, stuttered, and then got up and took off down a hallway, leaving our interviewer baffled.</p>]]></content><author><name></name></author><category term="satire" /><summary type="html"><![CDATA[Most companies only have rainbow logos in June. Google, however, has had a rainbow logo year-round, and they're not above gloating.]]></summary></entry><entry><title type="html">After Half the Florida Population Starves to Death, Governor DeSantis Suggests Reanimating the Dead as Workers</title><link href="https://scp-iota.github.io/satire/2025/03/31/florida-starves-reanimate-the-dead.html" rel="alternate" type="text/html" title="After Half the Florida Population Starves to Death, Governor DeSantis Suggests Reanimating the Dead as Workers" /><published>2025-03-31T00:00:00+00:00</published><updated>2025-03-31T00:00:00+00:00</updated><id>https://scp-iota.github.io/satire/2025/03/31/florida-starves-reanimate-the-dead</id><content type="html" xml:base="https://scp-iota.github.io/satire/2025/03/31/florida-starves-reanimate-the-dead.html"><![CDATA[<p>Since the mass starvation caused by Florida’s ban on eating grain products that caused the state’s population to be nearly halved, numerous restabilization programs have been implemented in a desperate attempt to curb the damage. Most recently, Governor DeSantis made a statement yesterday mentioning a possible new program to replace the lost workforce.</p>

<p>Called the “Necromancy Labor Project,” this initiative would temporarily direct significant funding to certain scientific institutions for the research and development of technology to reanimate and control corpses. Although nothing is confirmed yet and not many details are known, DeSantis says the intention of the program is to aid the restabilization of the Florida economy by filling jobs that are currently unfilled due to the starvation.</p>

<p>Economists have begun analyzing what kind of effects this type of program could have, and whether it would be enough to recover from this dire situation. Since the original statement, the Governor has also briefly mentioned in an interview that it might be worth considering expanding the program after recovery by reanimating the dead to replace the jobs of the living, maximizing efficient revenue and making employment obsolete.</p>

<blockquote>
  <p>“<em>It could also have the added benefit that, without jobs, many former workers would starve and die, which would increase the corpse supply.</em>”
~ Governor Ron DeSantis</p>
</blockquote>]]></content><author><name></name></author><category term="satire" /><summary type="html"><![CDATA[Satire: Mass starvation has many consequences, and for the state of Florida, apparently one of the most important is the reduced workforce - but that can be solved with a little necromancy]]></summary></entry><entry><title type="html">“Where are the eggs, Mr. President?” Golden Goose Owner Faces Major Losses From Rising Chicken Egg Value, Demands Answers</title><link href="https://scp-iota.github.io/satire/2025/02/28/eggs.html" rel="alternate" type="text/html" title="“Where are the eggs, Mr. President?” Golden Goose Owner Faces Major Losses From Rising Chicken Egg Value, Demands Answers" /><published>2025-02-28T00:00:00+00:00</published><updated>2025-02-28T00:00:00+00:00</updated><id>https://scp-iota.github.io/satire/2025/02/28/eggs</id><content type="html" xml:base="https://scp-iota.github.io/satire/2025/02/28/eggs.html"><![CDATA[<p>For twelve years, Rachel Bratcher from North Dakota has’t needed to worry about her financial situation. In November of 2013, in the field just outside her countryside house, she saw an egg with a very unusual attribute: it appeared golden.</p>

<blockquote>
  <p>“<em>I remember thinking it was a trick of the light - maybe the way the sun hit some kind of yellow bird egg - but when I held it, it felt heavy.</em>”</p>
</blockquote>

<p>Upon realizing that the “egg” was in fact a ovoid-shaped mass of solid gold metal, she spent roughly two weeks tracking down the bird that layed it. Since then, her annual income has skyrocketed even after quitting her job. That is, until recently, now that the increasing value of chicken eggs has threatened to make her investment obsolete.</p>

<blockquote>
  <p>“<em>At first I didn’t think I needed to worry about it; surely chicken eggs could never be more valuable than my gold… right? But it kept rising.</em>”</p>
</blockquote>

<p>In the interview, she described how this situation affected her politics:</p>

<blockquote>
  <p>“<em>When I saw the campaign ads for Donald Trump promising to make eggs cheaper, I knew what I needed to do. I voted for him and hoped he would save my investment.</em>”</p>
</blockquote>

<p>Regardless, the price of eggs has continued to increase, and today it finally surpassed Mrs. Bratcher’s gold revenue.
Despite the campaign promises, we have seen no attempts by the President to remedy this changing economy.</p>]]></content><author><name></name></author><category term="satire" /><summary type="html"><![CDATA[Satire: This owner of a goose that lays golden eggs hasn't needed to worry about money for years, but now the rising value of chicken eggs may make this major source of income obsolete. She's now demanding answers from President Trump about why he hasn't decreased inflation as promised.]]></summary></entry><entry><title type="html">Trump Signs Executive Order Banning Gravity</title><link href="https://scp-iota.github.io/satire/2025/02/15/executive-order-ban-gravity.html" rel="alternate" type="text/html" title="Trump Signs Executive Order Banning Gravity" /><published>2025-02-15T00:00:00+00:00</published><updated>2025-02-15T00:00:00+00:00</updated><id>https://scp-iota.github.io/satire/2025/02/15/executive-order-ban-gravity</id><content type="html" xml:base="https://scp-iota.github.io/satire/2025/02/15/executive-order-ban-gravity.html"><![CDATA[<p>Since the first day of his second term of office, President Trump has signed numerous executive orders. Some legal theorists have expressed concerns that a few of these orders overreach the powers of the Executive, but until now, none of them have gone so far as to attempt to claim authority over the laws of physics.</p>

<p>That changed today, when the President signed executive order “Protecting Freedom of Movement and Ending Physically Restrictive Systems.” The order will forbid all departments and operations of the Executive branch from “establishing, assisting, enabling, or acknowledging” any “systems which infringe the right of American citizens to their freedom of movement by causing persons or objects to be forced downward without direct intervention.”</p>

<p>Additionally, the order contains a provision forbidding federal agencies from “propagating the notion one’s rights of physical freedom can be restricted by so-called ‘laws of nature’” or from “providing funding or aid to any public or private entities which make such claims.” In theory, this line would remove funding from schools that teach the physics of gravity, as well as from research institutions that publish gravity-related studies.</p>]]></content><author><name></name></author><category term="satire" /><summary type="html"><![CDATA[Satire: Among the frenzy of Trump's executive orders, this one might make it hard to keep your feet on the ground]]></summary></entry><entry><title type="html">Rosalynn Carter Responds From Beyond the Grave to Greg Abbott’s Condolences</title><link href="https://scp-iota.github.io/satire/2024/12/31/rosalynn-carter-condolences.html" rel="alternate" type="text/html" title="Rosalynn Carter Responds From Beyond the Grave to Greg Abbott’s Condolences" /><published>2024-12-31T00:00:00+00:00</published><updated>2024-12-31T00:00:00+00:00</updated><id>https://scp-iota.github.io/satire/2024/12/31/rosalynn-carter-condolences</id><content type="html" xml:base="https://scp-iota.github.io/satire/2024/12/31/rosalynn-carter-condolences.html"><![CDATA[<p>Throughout history, many people have believed in the possibility of communicating beyond the veil with the spirits of deceased people. From séance, to mediumship, to Ouija boards, people have come up with many ways to supposedly contact the great beyond; the most recent one, apparently, is to send your condolences.</p>

<p>A statement issued by Texas governor Greg Abbott contained a sentence sending his condolences to Jimmy Carter’s wife, Rosalynn, before it was later removed.</p>

<blockquote>
  <p>“<em>Cecilia and I send our prayers and deepest condolences to First Lady Rosalynn Carter and the entire Carter family.</em>”</p>
</blockquote>

<p>This line had caused public confusion because Rosalynn passed away in November of last year. Rosalynn herself, however, heeded the call from beyond the veil, leaving this message scrawled on a mirror in the Texas Governor’s Mansion:</p>

<blockquote>
  <p>“<em>I appreciate your kind words during this emotional time. It is not often that those in the world of the living consider those who have ascended, so I thank you for your forethought in addressing me.</em>”</p>
</blockquote>

<p>Several spiritualists and paranormal activity investigators are already planning trips to Austin to learn more about this occurrence.</p>]]></content><author><name></name></author><category term="satire" /><summary type="html"><![CDATA[Satire: A mistake in Greg Abbott's statement in honor of the recently departed Jimmy Carter accidentally summoned the ghost of his wife]]></summary></entry></feed>