<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="https://riceball.com/wp-content/plugins/pretty-rss-feeds/xslt/pretty-feed.xsl" type="text/xsl" media="screen" ?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Human Learning - 🍙</title>
	<atom:link href="https://riceball.com/category/human-learning/feed/" rel="self" type="application/rss+xml" />
	<link>https://riceball.com</link>
	<description></description>
	<lastBuildDate>Tue, 13 Oct 2026 06:50:15 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.4</generator>

<image>
	<url>https://riceball.com/wp-content/uploads/sites/2/2025/10/onigiri-150x150.png</url>
	<title>Human Learning - 🍙</title>
	<link>https://riceball.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>PHP Traits</title>
		<link>https://riceball.com/2026/10/12/php-traits/</link>
					<comments>https://riceball.com/2026/10/12/php-traits/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Tue, 13 Oct 2026 02:27:58 +0000</pubDate>
				<category><![CDATA[Human Learning]]></category>
		<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=31041</guid>

					<description><![CDATA[<p>Just read this. Nice take: https://generalistprogrammer.com/tutorials/php-traits-complete-guide Thinking out loud&#8230; tell me if I&#8217;m wrong. I&#8217;m mulling the idea of using Traits to compose static classes with no state. The static class would act as a Facade. It could implement an Interface. The static class would be paired with a state object, which could contain all [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/10/12/php-traits/">PHP Traits</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">Just read this. Nice take:</p>



<p class="wp-block-paragraph"><a href="https://generalistprogrammer.com/tutorials/php-traits-complete-guide">https://generalistprogrammer.com/tutorials/php-traits-complete-guide</a></p>



<h3 class="wp-block-heading">Thinking out loud&#8230; tell me if I&#8217;m wrong.</h3>



<p class="wp-block-paragraph">I&#8217;m mulling the idea of using Traits to compose static classes with no state.</p>



<p class="wp-block-paragraph">The static class would act as a Facade. It could implement an Interface.</p>



<p class="wp-block-paragraph">The static class would be paired with a state object, which could contain all the state. This pairing would allow a clean separation of data from algorithms.</p>



<p class="wp-block-paragraph">The Traits would contain no state. State, or portions of state, are passed in as parameters to methods.</p>



<p class="wp-block-paragraph">Maybe it would be possible to create no-state objects, to allow for class-based dispatch (a kind of polymorphism).</p>



<h3 class="wp-block-heading">Notebooking</h3>



<p class="wp-block-paragraph">This is the first draft. It worked, but it it <strong>useful</strong>?</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-Deja-Vu-Mono.ttf" style="font-size:.875rem;font-family:Code-Pro-Deja-Vu-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#F8F8F2;--cbp-line-number-width:calc(3 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;?php

interface AnimalInterface {
    static function sayHello(Animal $a);
    static function doPoo(Animal $a);
    static function doEat(Animal $a);
}

class Animal implements AnimalInterface {
  use Speak;
  use Poop;
  use Eat;
}

trait Speak {
    static function sayHello(Animal $a) 
    {
        echo 'Says: ' . $a->speech . "\n";
    }
}

trait Poop {
    static function doPoo(Animal $a)
    {
        echo 'Defecates: ' . $a->defecate . "\n";
    }
}

trait Eat {
    static function doEat(Animal $a)
    {
        echo 'Eats: ' . $a->food . "\n";
    }
}

class AnimalState {
    public $state = [];

    function init() 
    {
        $this->state&#91;'dog'&#93; = new Dog();
        $this->state&#91;'cat'&#93; = new Cat();
        $this->state&#91;'bird'&#93; = new Bird();
    }
}

class Dog extends Animal {
    public readonly string $speech;
    public readonly string $defecate;
    public readonly string $food;
    public readonly int $age;

    function __construct($age = 1) 
    {
        $this->speech = 'woof';
        $this->defecate = 'dog loaf';
        $this->food = 'kibble';
        $this->age = $age;
    }
}

class Cat extends Animal {
    public readonly string $speech;
    public readonly string $defecate;
    public readonly string $food;
    public readonly int $age;

    function __construct($age = 1) 
    {
        $this->speech = 'mew';
        $this->defecate = 'hairpoo';
        $this->food = 'tuna';
        $this->age = $age;
    }
}

class Bird extends Animal {
    public readonly string $speech;
    public readonly string $defecate;
    public readonly string $food;
    public readonly int $age;

    function __construct($age = 1) 
    {
        $this->speech = 'chirp';
        $this->defecate = 'birdstool';
        $this->food = 'millet';
        $this->age = $age;
    }
}

$s = new AnimalState();
$s->init();

echo "\ndog\n";
Animal::sayHello( $s->state&#91;'dog'&#93; );
Animal::doPoo( $s->state&#91;'dog'&#93; );
Animal::doEat( $s->state&#91;'dog'&#93; );
echo "\ncat\n";
Animal::sayHello( $s->state&#91;'cat'&#93; );
Animal::doPoo( $s->state&#91;'cat'&#93; );
Animal::doEat( $s->state&#91;'cat'&#93; );
echo "\nbird\n";
Animal::sayHello( $s->state&#91;'bird'&#93; );
Animal::doPoo( $s->state&#91;'bird'&#93; );
Animal::doEat( $s->state&#91;'bird'&#93; );

// we create a new bird to replace the old one
$s->state&#91;'bird'&#93; = new Bird(5);

echo "\nthe new bird has age: " . $s->state&#91;'bird'&#93;->age . "\n\n";

var_dump($s);</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">&lt;?</span><span style="color: #BD93F9">php</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">interface</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">AnimalInterface</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">static</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">sayHello</span><span style="color: #F8F8F2">(</span><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #F8F8F2"> $a);</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">static</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">doPoo</span><span style="color: #F8F8F2">(</span><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #F8F8F2"> $a);</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">static</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">doEat</span><span style="color: #F8F8F2">(</span><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #F8F8F2"> $a);</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">class</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD">Animal</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">implements</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">AnimalInterface</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #FF79C6">use</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Speak</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #FF79C6">use</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Poop</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #FF79C6">use</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Eat</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">trait</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Speak</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">static</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">sayHello</span><span style="color: #F8F8F2">(</span><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #F8F8F2"> $a) </span></span>
<span class="line"><span style="color: #F8F8F2">    {</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #8BE9FD">echo</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">Says: </span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">.</span><span style="color: #F8F8F2"> $a</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">speech </span><span style="color: #FF79C6">.</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&quot;</span><span style="color: #FF79C6">\n</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">trait</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Poop</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">static</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">doPoo</span><span style="color: #F8F8F2">(</span><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #F8F8F2"> $a)</span></span>
<span class="line"><span style="color: #F8F8F2">    {</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #8BE9FD">echo</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">Defecates: </span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">.</span><span style="color: #F8F8F2"> $a</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">defecate </span><span style="color: #FF79C6">.</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&quot;</span><span style="color: #FF79C6">\n</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">trait</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Eat</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">static</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">doEat</span><span style="color: #F8F8F2">(</span><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #F8F8F2"> $a)</span></span>
<span class="line"><span style="color: #F8F8F2">    {</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #8BE9FD">echo</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">Eats: </span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">.</span><span style="color: #F8F8F2"> $a</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">food </span><span style="color: #FF79C6">.</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&quot;</span><span style="color: #FF79C6">\n</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">class</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD">AnimalState</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> $state </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> [];</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">init</span><span style="color: #F8F8F2">() </span></span>
<span class="line"><span style="color: #F8F8F2">    {</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">dog</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">new</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Dog</span><span style="color: #F8F8F2">();</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">cat</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">new</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Cat</span><span style="color: #F8F8F2">();</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">bird</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">new</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Bird</span><span style="color: #F8F8F2">();</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">class</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD">Dog</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">extends</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">string</span><span style="color: #F8F8F2"> $speech;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">string</span><span style="color: #F8F8F2"> $defecate;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">string</span><span style="color: #F8F8F2"> $food;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">int</span><span style="color: #F8F8F2"> $age;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD">__construct</span><span style="color: #F8F8F2">($age </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">) </span></span>
<span class="line"><span style="color: #F8F8F2">    {</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">speech </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">woof</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">defecate </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">dog loaf</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">food </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">kibble</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">age </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> $age;</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">class</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD">Cat</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">extends</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">string</span><span style="color: #F8F8F2"> $speech;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">string</span><span style="color: #F8F8F2"> $defecate;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">string</span><span style="color: #F8F8F2"> $food;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">int</span><span style="color: #F8F8F2"> $age;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD">__construct</span><span style="color: #F8F8F2">($age </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">) </span></span>
<span class="line"><span style="color: #F8F8F2">    {</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">speech </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">mew</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">defecate </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">hairpoo</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">food </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">tuna</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">age </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> $age;</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">class</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD">Bird</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">extends</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">string</span><span style="color: #F8F8F2"> $speech;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">string</span><span style="color: #F8F8F2"> $defecate;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">string</span><span style="color: #F8F8F2"> $food;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">public</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">readonly</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">int</span><span style="color: #F8F8F2"> $age;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD">__construct</span><span style="color: #F8F8F2">($age </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">) </span></span>
<span class="line"><span style="color: #F8F8F2">    {</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">speech </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">chirp</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">defecate </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">birdstool</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">food </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">millet</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">$this</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">age </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> $age;</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">$s </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">new</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">AnimalState</span><span style="color: #F8F8F2">();</span></span>
<span class="line"><span style="color: #F8F8F2">$s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #50FA7B">init</span><span style="color: #F8F8F2">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #8BE9FD">echo</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&quot;</span><span style="color: #FF79C6">\n</span><span style="color: #F1FA8C">dog</span><span style="color: #FF79C6">\n</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #FF79C6">::</span><span style="color: #50FA7B">sayHello</span><span style="color: #F8F8F2">( $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">dog</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; );</span></span>
<span class="line"><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #FF79C6">::</span><span style="color: #50FA7B">doPoo</span><span style="color: #F8F8F2">( $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">dog</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; );</span></span>
<span class="line"><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #FF79C6">::</span><span style="color: #50FA7B">doEat</span><span style="color: #F8F8F2">( $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">dog</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; );</span></span>
<span class="line"><span style="color: #8BE9FD">echo</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&quot;</span><span style="color: #FF79C6">\n</span><span style="color: #F1FA8C">cat</span><span style="color: #FF79C6">\n</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #FF79C6">::</span><span style="color: #50FA7B">sayHello</span><span style="color: #F8F8F2">( $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">cat</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; );</span></span>
<span class="line"><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #FF79C6">::</span><span style="color: #50FA7B">doPoo</span><span style="color: #F8F8F2">( $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">cat</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; );</span></span>
<span class="line"><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #FF79C6">::</span><span style="color: #50FA7B">doEat</span><span style="color: #F8F8F2">( $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">cat</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; );</span></span>
<span class="line"><span style="color: #8BE9FD">echo</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&quot;</span><span style="color: #FF79C6">\n</span><span style="color: #F1FA8C">bird</span><span style="color: #FF79C6">\n</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #FF79C6">::</span><span style="color: #50FA7B">sayHello</span><span style="color: #F8F8F2">( $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">bird</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; );</span></span>
<span class="line"><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #FF79C6">::</span><span style="color: #50FA7B">doPoo</span><span style="color: #F8F8F2">( $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">bird</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; );</span></span>
<span class="line"><span style="color: #8BE9FD; font-style: italic">Animal</span><span style="color: #FF79C6">::</span><span style="color: #50FA7B">doEat</span><span style="color: #F8F8F2">( $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">bird</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; );</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4">// we create a new bird to replace the old one</span></span>
<span class="line"><span style="color: #F8F8F2">$s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">bird</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93; </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">new</span><span style="color: #F8F8F2"> </span><span style="color: #8BE9FD; font-style: italic">Bird</span><span style="color: #F8F8F2">(</span><span style="color: #BD93F9">5</span><span style="color: #F8F8F2">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #8BE9FD">echo</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&quot;</span><span style="color: #FF79C6">\n</span><span style="color: #F1FA8C">the new bird has age: </span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">.</span><span style="color: #F8F8F2"> $s</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">state&#91;</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">bird</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">&#93;</span><span style="color: #FF79C6">-&gt;</span><span style="color: #F8F8F2">age </span><span style="color: #FF79C6">.</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&quot;</span><span style="color: #FF79C6">\n\n</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #8BE9FD">var_dump</span><span style="color: #F8F8F2">($s);</span></span></code></pre></div>



<p class="wp-block-paragraph">This code has interesting qualities.</p>



<p class="wp-block-paragraph">First, the AnimalState is the only thing that holds state.</p>



<p class="wp-block-paragraph">Everything else doesn&#8217;t hold state.</p>



<p class="wp-block-paragraph">The Dog, Cat, and Bird types are stateful classes, and instantiated, but aren&#8217;t mutable. All the properties are <code>readonly</code>.</p>



<p class="wp-block-paragraph">Look at line 109. I cannot set the value of $age, because it&#8217;s readonly, but I can initialize a new Bird of 5 years old. Some languages also have this restriction, where named values are immutable.</p>



<p class="wp-block-paragraph"><strong>Method names and property names matter</strong>. For all the parts to work, they must conform. The AnimalInterface enforces the method names. <em>Nothing enforces the property names.</em></p>



<p class="wp-block-paragraph">Is it useful? I&#8217;m not sure. It&#8217;s a lot of extra boilerplate.</p>



<h4 class="wp-block-heading">What&#8217;s Missing?</h4>



<p class="wp-block-paragraph">PHP 8.3.6 doesn&#8217;t support <code>public readonly protected(set)</code>. If it did, I think I could move the variable declarations up into Animal, and it would act like a contract for the subclasses.</p>



<p class="wp-block-paragraph">I tried moving the properties like $speech into the Trait (rather than in the Class like it is above). It linted with php -l, failed with phpstan, and didn&#8217;t run. It refused to initialize the $speech property from the Trait because it was out of the Dog scope.</p>



<p class="wp-block-paragraph">Here&#8217;s the <code>json_encode($s)</code> output:</p>


<pre class="wp-block-code"><span><code class="hljs language-json shcb-wrap-lines">{
    \<span class="hljs-attr">"state\": {
        \"dog\": {
            \"speech\": \"woof\",
            \"defecate\": \"dog loaf\",
            \"food\": \"kibble\",
            \"age\": 1
        },
        \"cat\": {
            \"speech\": \"mew\",
            \"defecate\": \"hairpoo\",
            \"food\": \"tuna\",
            \"age\": 1
        },
        \"bird\": {
            \"speech\": \"chirp\",
            \"defecate\": \"birdstool\",
            \"food\": \"millet\",
            \"age\": 5
        }
    }
}</span></code></span></pre>


<p class="wp-block-paragraph">It&#8217;s OK, but it needs a _class property so it can rehydrate correctly (which is easy to add).</p>



<p class="wp-block-paragraph"><code>$s->state['bird']->age = 100;</code> // this code passes php&#8217;s lint, but it&#8217;s a bug.</p>



<p class="wp-block-paragraph">Ideally, this bug would be caught at compile time, because assigning a value to a readonly property throws an error when run.</p>



<p class="wp-block-paragraph">I found this <a href="https://guven.atbakan.com/blog/php-linters-i-cant-live-without-them/">good post about PHP linters</a>.</p>



<p class="wp-block-paragraph"><strong><a href="https://phpstan.org/user-guide/getting-started">phpstan</a> found the bug with &#8211;level 3.</strong></p>



<p class="wp-block-paragraph">(I tried installing <a href="https://packagist.org/packages/vimeo/psalm#dev-master">psalm</a>, but my PHP version was too low.)</p>



<h3 class="wp-block-heading">More Thinking</h3>



<p class="wp-block-paragraph">In a real-world scenario, you would probably have a more elaborate state structure of nested arrays, terminating in these read-only objects, or arrays of read-only objects.</p>



<p class="wp-block-paragraph">Your application would be a bunch of Interfaces and implementation, read-only objects, and some logic to make the app happen.</p>



<p class="wp-block-paragraph">I think you&#8217;d have lots of code like this:</p>


<pre class="wp-block-code"><span><code class="hljs language-php shcb-wrap-lines">$s-&gt;state&#91;<span class="hljs-string">'x'</span>]&#91;<span class="hljs-string">'y'</span>]&#91;<span class="hljs-string">'z'</span>] = 
    SomeService::doAThingTo( $s-&gt;state&#91;<span class="hljs-string">'x'</span>]&#91;<span class="hljs-string">'y'</span>]&#91;<span class="hljs-string">'z'</span>] );</code></span></pre>


<p class="wp-block-paragraph">You&#8217;d have that mixed in with a lot of traditional logic.</p>



<p class="wp-block-paragraph">You&#8217;d write functions to manipulate the state yourself.</p>



<p class="wp-block-paragraph">Some things could get easy, like saving the app state with each request: use a flatter namespace, and save it to Redis. (Examples: &#8216;config&#8217;, &#8216;app&#8217;, &#8216;user&#8217;, &#8216;documents&#8217;.)</p>



<p class="wp-block-paragraph">Retrieve the state from Redis. Add a feature to lazy-load the data, and write subsets of the state.</p>



<p class="wp-block-paragraph">AnimalState doesn&#8217;t need to be initialized with objects. It&#8217;s just an array. It should probably use magic methods to allow $s->dog to return the Dog object.</p>



<p class="wp-block-paragraph">Setter magic methods could verify that the new value is of the same class as the old value; so a Dog object must be replaced with another Dog object.</p>



<p class="wp-block-paragraph">DocBlocks might be able to add a type annotation, but I don&#8217;t know if it would be honored.</p>



<p class="wp-block-paragraph">Magic getters could map a key like &#8216;dog&#8217; to a property named &#8216;_dog&#8217;, which has a type signature that phpstan might recognize. The magic getter should be coded up with a switch statement rather than doing string mangling and isset().</p>



<p class="wp-block-paragraph">Example:</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-keyword">public</span> readonly Dog $_dog;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__get</span><span class="hljs-params">($key)</span>: <span class="hljs-title">Animal</span>
</span>{
    <span class="hljs-keyword">switch</span>($key) {
        <span class="hljs-keyword">case</span> <span class="hljs-string">'dog'</span>: <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;_dog;
        <span class="hljs-keyword">default</span>: <span class="hljs-comment">// some error situation, die nicely</span>
    }
}</code></span></pre>


<p class="wp-block-paragraph">The robot overlords can understand that code path, and won&#8217;t need to &#8220;reason&#8221; about some string mangling code like this (code not checked):</p>


<pre class="wp-block-code"><span><code class="hljs language-php shcb-wrap-lines"><span class="hljs-keyword">public</span> $state;
...
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__get</span><span class="hljs-params">($key)</span>: <span class="hljs-title">object</span> 
</span>{
    $kkey = <span class="hljs-string">"_$key"</span>;
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">isset</span>(<span class="hljs-keyword">$this</span>-&gt;state&#91;$kkey])) {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;state&#91;$kkey];
    } <span class="hljs-keyword">else</span> {
       <span class="hljs-comment">// die politely</span>
    }
}</code></span></pre>


<p class="wp-block-paragraph">I realize the latter is more general, but that begs the question: should everything be generalized and flexible at runtime, even if it&#8217;s the thing holding the application state?</p>



<p class="wp-block-paragraph">The answer in 2026 is &#8220;no&#8221;.</p><p>The post <a href="https://riceball.com/2026/10/12/php-traits/">PHP Traits</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/10/12/php-traits/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Falafel</title>
		<link>https://riceball.com/2026/10/03/falafel/</link>
					<comments>https://riceball.com/2026/10/03/falafel/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sat, 03 Oct 2026 18:43:57 +0000</pubDate>
				<category><![CDATA[Human Learning]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=30712</guid>

					<description><![CDATA[<p>Log of attempts. Recipe for Falafel ■ Ingredients (for 20 pieces)&#8211; 400 grams of dried chickpeas.&#8211; Handful of leaf parsley.&#8211; 1 large onion.&#8211; A few drops of sesame oil.&#8211; 2 to 3 tablespoons of wheat flour.&#8211; 1 or 2 cloves of garlic.&#8211; 1 teaspoon of cumin powder.&#8211; 1 teaspoon of cayenne pepper.&#8211; Pinch of salt. [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/10/03/falafel/">Falafel</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">Log of attempts.</p>



<ol class="wp-block-list">
<li>Don&#8217;t have the recipe. It was B-. I really liked it.</li>
</ol>



<h1 class="wp-block-heading">Recipe for Falafel</h1>



<h1 class="wp-block-heading">■ Ingredients</h1>



<p class="wp-block-paragraph">(for 20 pieces)<br>&#8211; 400 grams of dried chickpeas.<br>&#8211; Handful of leaf parsley.<br>&#8211; 1 large onion.<br>&#8211; A few drops of sesame oil.<br>&#8211; 2 to 3 tablespoons of wheat flour.<br>&#8211; 1 or 2 cloves of garlic.<br>&#8211; 1 teaspoon of cumin powder.<br>&#8211; 1 teaspoon of cayenne pepper.<br>&#8211; Pinch of salt.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">My modifications: jalapeno instead of cayenne, a little less onion and a lot more parsley.</p>



<h1 class="wp-block-heading">■ Preparation</h1>



<p class="wp-block-paragraph">&#8211; Soak the chickpeas overnight in cold water. You will notice that the volume more or less doubles. Don&#8217;t use canned chickpeas for this recipe, they are already cooked.<br>&#8211; Cut the garlic and onion into large pieces.<br>&#8211; Remove the stalks from the parsley and fine the leaves.<br>&#8211; Put the chickpeas with all ingredients in a blender and grind them until you get a crumbly dough. Make sure there are no longer large pieces in it, but don&#8217;t blend the dough for too long.<br>&#8211; Wet your hands and roll small balls off the dough. You choose the diameter yourself, but smaller balls are fried faster.<br>&#8211; Fry them until they are golden yellow on both sides.<br>&#8211; Make a delicious dip sauce to your own taste.</p>



<p class="wp-block-paragraph"></p><p>The post <a href="https://riceball.com/2026/10/03/falafel/">Falafel</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/10/03/falafel/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Adapting Traditional OOP Style to the LLM World</title>
		<link>https://riceball.com/2026/09/29/adapting-traditional-oop-style-to-the-llm-world/</link>
					<comments>https://riceball.com/2026/09/29/adapting-traditional-oop-style-to-the-llm-world/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 30 Sep 2026 02:45:29 +0000</pubDate>
				<category><![CDATA[Human Learning]]></category>
		<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[Thaura]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=30654</guid>

					<description><![CDATA[<p>(Another Thaura Work product. Again, haven&#8217;t checked, but lots of good ideas in here.) New ways to use old structures to help LLMs write better code. Techniques to reduce token use, reduce context size, reduce errors. Adapting Traditional OOP Style Classic object-oriented design — inheritance hierarchies, polymorphic dispatch, encapsulated state — predates LLMs by decades. [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/09/29/adapting-traditional-oop-style-to-the-llm-world/">Adapting Traditional OOP Style to the LLM World</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">(Another Thaura Work product. Again, haven&#8217;t checked, but lots of good ideas in here.)</p>



<p class="wp-block-paragraph">New ways to use old structures to help LLMs write better code. Techniques to reduce token use, reduce context size, reduce errors.</p>



<h2 class="wp-block-heading">Adapting Traditional OOP Style</h2>



<p class="wp-block-paragraph">Classic object-oriented design — inheritance hierarchies, polymorphic dispatch, encapsulated state — predates LLMs by decades. Much of what made OOP ergonomic for humans (deep class trees, implicit constructor injection, framework-managed lifecycles) introduces exactly the kind of <em>implicit decisions</em> that hurt one-shot generation. The good news: you can keep the spirit of OOP while stripping out the parts that confuse a model.</p>



<h3 class="wp-block-heading">Inheritance → Composition + Interfaces</h3>



<p class="wp-block-paragraph">Deep <code>extends</code> chains force the model to track overridden methods across multiple files, guess which superclass field is shadowing which, and infer initialization order. Adaptation:</p>



<ul class="wp-block-list">
<li><strong>Prefer interfaces / traits / protocols over base classes.</strong> A flat <code>interface PaymentProcessor { process(order: Order): Result }</code> gives the model a complete contract in one place. No diamond problems, no super-call ordering to reason about.</li>



<li><strong>Use composition for shared behavior.</strong> Mixins, embedded structs, or trait implementations (<code>impl Display for MyType</code>) are self-contained blocks the model can generate without knowing the rest of the hierarchy.</li>



<li><strong>If you must inherit, keep depth ≤ 2.</strong> One concrete base + one leaf is manageable; three levels with abstract intermediates start to exceed what the model tracks reliably in a single pass.</li>
</ul>



<h3 class="wp-block-heading">Encapsulation → Explicit Data Structures</h3>



<p class="wp-block-paragraph">Private fields with getters/setters hide data flow behind method calls the model must predict. Adaptation:</p>



<ul class="wp-block-list">
<li><strong>Expose plain data structures</strong> (structs, records, frozen objects) at boundaries. The model sees the shape directly instead of inferring it from accessor pairs.</li>



<li><strong>Reserve methods for behavior</strong>, not for field access. If a &#8220;method&#8221; just returns a field, make the field public (or readonly) and delete the getter. Fewer indirection layers means fewer places the model can invent a nonexistent accessor.</li>



<li><strong>Make mutability intentional and visible.</strong> A struct with all-public fields communicates &#8220;data container.&#8221; A class with private state and mutating methods signals &#8220;behavior owner.&#8221; Mixing both in one type forces the model to guess the invariant.</li>
</ul>



<h3 class="wp-block-heading">Polymorphism → Tagged Unions + Pattern Matching</h3>



<p class="wp-block-paragraph">Runtime dynamic dispatch (<code>obj.handle()</code> where the actual type depends on construction site) requires the model to enumerate every possible subclass. Adaptation:</p>



<ul class="wp-block-list">
<li><strong>Replace runtime polymorphism with sum types + exhaustive match</strong> wherever the set of cases is closed. <code>enum Shape { Circle(f64), Rect(f64, f64) }</code> matched in one function is unambiguous; a <code>Shape</code> interface with ten subclasses scattered across modules is not.</li>



<li><strong>For open-ended extensibility</strong> (plugin systems, event handlers), use an explicit registry or visitor pattern rather than relying on the model to discover all overrides. The registry is a single lookup table the model can read.</li>



<li><strong>Sealed hierarchies beat open ones.</strong> If the compiler enforces exhaustiveness (Kotlin <code>sealed</code>, Scala sealed, TypeScript discriminated unions), the model knows the case list is complete. Open hierarchies invite phantom branches.</li>
</ul>



<h3 class="wp-block-heading">Dependency Injection → Explicit Constructor Parameters</h3>



<p class="wp-block-paragraph">Frameworks that inject dependencies via annotations, reflection, or container magic hide the dependency graph. The model can&#8217;t see what a class actually needs until it reads the DI configuration. Adaptation:</p>



<ul class="wp-block-list">
<li><strong>Pass dependencies through constructors explicitly.</strong> <code>fn new(db: &amp;Pool, cache: &amp;Cache)</code> is visible at the call site. <code>@Inject</code> annotations require reading a separate wiring file the model may not have in context.</li>



<li><strong>Keep constructor arity low (≤ 4).</strong> Beyond that, bundle related deps into a config/options struct. Long parameter lists are where models drop arguments or swap types.</li>



<li><strong>Avoid builder-pattern fluency for core types.</strong> Fluent builders (<code>new Widget().red().big().build()</code>) scatter construction logic across chained calls. A single constructor call with a struct literal is easier to generate correctly.</li>
</ul>



<h3 class="wp-block-heading">Framework Magic → Plain Entry Points</h3>



<p class="wp-block-paragraph">Spring beans, Rails controllers, Angular decorators, and similar frameworks interpose lifecycle hooks, serialization, and routing logic between your code and its observable behavior. Adaptation:</p>



<ul class="wp-block-list">
<li><strong>Isolate framework glue in thin adapters.</strong> Keep business logic in plain functions/classes with no framework annotations. The adapter translates HTTP request → function call → response. The model generates the interesting part (logic) without needing to satisfy framework constraints simultaneously.</li>



<li><strong>Prefer functional entry points for pure computation.</strong> A controller that calls <code>calculate_total(items, discount_code)</code> is testable and generatable independently of the web framework. Embedding that calculation inside a decorated class method couples two concerns the model must get right at once.</li>



<li><strong>Document the framework contract in the prompt if unavoidable.</strong> If the target code must be a Spring <code>@Service</code> or a React component, include one minimal working example in the prompt. One concrete exemplar reduces hallucination more than any amount of prose description.</li>
</ul>



<h3 class="wp-block-heading">State Machines → Enum-Driven Flows</h3>



<p class="wp-block-paragraph">Implicit state held in boolean flags (<code>isLoading</code>, <code>hasError</code>, <code>isSubmitted</code>) creates combinatorial explosion the model struggles to navigate. Adaptation:</p>



<ul class="wp-block-list">
<li><strong>Model explicit states as enums.</strong> <code>enum CheckoutState { Idle, FillingCart, ValidatingPayment, Processing, Complete(Error?) }</code> makes invalid transitions impossible and gives the model a finite, named space to work in.</li>



<li><strong>Transition functions take <code>(state, event) → new_state</code>.</strong> Pure transition functions are trivially verifiable and easy to generate. Mutating a stateful object&#8217;s internal booleans is not.</li>



<li><strong>Guard clauses over nested conditionals.</strong> <code>match state { Idle => ..., Processing => ... }</code> beats four levels of <code>if (flag1 &amp;&amp; !flag2 || flag3)</code> that the model must untangle.</li>
</ul>



<h3 class="wp-block-heading">Summary Checklist</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Classic OOP habit</th><th>LLM-friendly adaptation</th><th>Why it helps</th></tr></thead><tbody><tr><td>Deep inheritance tree</td><td>Interface + composition, depth ≤ 2</td><td>Flat contracts, no shadow tracking</td></tr><tr><td>Private fields + getters</td><td>Public/frozen data structs</td><td>Visible shape, no invented accessors</td></tr><tr><td>Runtime polymorphism</td><td>Sum types + exhaustive match</td><td>Closed case set, compiler-checked</td></tr><tr><td>Annotation-based DI</td><td>Explicit constructor params</td><td>Dependency graph visible at call site</td></tr><tr><td>Builder pattern</td><td>Single constructor + options struct</td><td>One expression, not a chain</td></tr><tr><td>Framework-decorated logic</td><td>Thin adapter + pure core function</td><td>Separates concerns the model handles independently</td></tr><tr><td>Boolean-flag state</td><td>Enum-driven state machine</td><td>Finite named states, pure transitions</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">The overarching principle is the same as the rest of this article: <strong>remove implicit decisions</strong>. Traditional OOP optimizes for human maintainability in large teams over years — hiding internals, deferring binding, distributing behavior across a hierarchy. LLM one-shot generation optimizes for a different constraint: everything relevant must be visible, local, and unambiguous within a single context window. You don&#8217;t abandon OOP thinking; you flatten it so the model doesn&#8217;t have to reconstruct the hidden architecture from fragments.</p><p>The post <a href="https://riceball.com/2026/09/29/adapting-traditional-oop-style-to-the-llm-world/">Adapting Traditional OOP Style to the LLM World</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/09/29/adapting-traditional-oop-style-to-the-llm-world/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Language Characteristics that Help LLMs Write Better Code</title>
		<link>https://riceball.com/2026/09/28/language-characteristics-that-help-llms-write-better-code/</link>
					<comments>https://riceball.com/2026/09/28/language-characteristics-that-help-llms-write-better-code/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Tue, 29 Sep 2026 02:19:57 +0000</pubDate>
				<category><![CDATA[Human Learning]]></category>
		<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[Elm]]></category>
		<category><![CDATA[Thaura]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=30651</guid>

					<description><![CDATA[<p>(Written by Thaura Work. I haven&#8217;t checked it. I&#8217;ve been learning Elm, so there might be some bias it picked up somewhere in my files.) A quick-reference list of language features and conventions that make one-shot code generation more reliable. The common thread: predictability. Features that appear frequently in training data, parse unambiguously, and leave [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/09/28/language-characteristics-that-help-llms-write-better-code/">Language Characteristics that Help LLMs Write Better Code</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">(Written by Thaura Work. I haven&#8217;t checked it. I&#8217;ve been learning Elm, so there might be some bias it picked up somewhere in my files.)</p>



<p class="wp-block-paragraph">A quick-reference list of language features and conventions that make one-shot code generation more reliable. The common thread: <strong>predictability</strong>. Features that appear frequently in training data, parse unambiguously, and leave few implicit choices produce fewer hallucinations and fewer subtle bugs.</p>



<h2 class="wp-block-heading">Type System &amp; Static Structure</h2>



<ul class="wp-block-list">
<li><strong>Explicit type annotations.</strong> Languages with strong static typing (TypeScript, Rust, Go, Java) constrain the solution space dramatically. An annotation like <code>fn process(input: Vec&lt;u8&gt;) -&gt; Result&lt;String, Error&gt;</code> tells the model exactly what goes in and comes out, eliminating an entire class of guessing.</li>



<li><strong>Algebraic / sum types.</strong> Enums, tagged unions, sealed classes, and <code>Result&lt;T, E&gt;</code> force exhaustive handling. The model can&#8217;t silently forget a case the way it can with a bare integer or string status code.</li>



<li><strong>Optionality made explicit.</strong> <code>Option&lt;T&gt;</code>, nullable markers, or required-field syntax prevent &#8220;did I check for null?&#8221; ambiguity from leaking into generated logic.</li>
</ul>



<h2 class="wp-block-heading">Naming &amp; Conventions</h2>



<ul class="wp-block-list">
<li><strong>Descriptive, conventional identifiers.</strong> Names that follow community norms (<code>getUserName</code>, not <code>gn()</code>) match high-frequency patterns in training data. The model essentially autocomplete-s from convention.</li>



<li><strong>Standard library names used as-is.</strong> Reaching for <code>collections.defaultdict</code> instead of inventing a helper keeps the output verifiable and familiar.</li>
</ul>



<h2 class="wp-block-heading">Syntax Predictability</h2>



<ul class="wp-block-list">
<li><strong>Uniform function/method call syntax.</strong> Consistent <code>f(x)</code> across the language means the model rarely fumbles call shapes. Languages mixing macro invocations, operator overloading, and special dispatch forms are harder to get right blind.</li>



<li><strong>No hidden mutation or side effects baked into syntax.</strong> Properties, getters/setters, and overloaded operators introduce behavior the model must infer. Plain functions and plain fields are safer bets.</li>



<li><strong>Single, obvious control-flow forms.</strong> One canonical <code>for x in items:</code> loop beats five dialects. When a language has many ways to express the same thing, the model picks whichever was most frequent in its slice of training data — which may not be your house style.</li>
</ul>



<h2 class="wp-block-heading">Module &amp; Import Clarity</h2>



<ul class="wp-block-list">
<li><strong>Explicit imports.</strong> Languages where every symbol must be imported (Go, ES modules, Rust <code>use</code>) give the model a clear contract. Implicit global namespaces increase the chance of name collisions and wrong-symbol guesses.</li>



<li><strong>Flat, predictable module paths.</strong> Deep dynamic import chains are harder for the model to resolve correctly than shallow, named ones.</li>
</ul>



<h2 class="wp-block-heading">Error Handling</h2>



<ul class="wp-block-list">
<li><strong>Structured errors over exceptions-as-control-flow.</strong> Returning error values or using typed result types is easier for the model to wire up correctly than try/catch ladders with implicit propagation.</li>



<li><strong>One idiomatic recovery path.</strong> If the ecosystem has a single accepted pattern (e.g., Rust&#8217;s <code>?</code> operator), the model converges on it reliably.</li>
</ul>



<h2 class="wp-block-heading">Immutability &amp; Data Flow</h2>



<ul class="wp-block-list">
<li><strong>Default-immutability languages</strong> (Rust ownership, immutable-by-default JS bindings via <code>const</code> discipline, Clojure values) reduce the state-space the model must track. Fewer aliasing surprises mean fewer off-by-one-mutation bugs.</li>



<li><strong>Pure-function-friendly design.</strong> Functions whose output depends only on inputs are trivially composable and easy for the model to reason about step by step.</li>
</ul>



<h2 class="wp-block-heading">Formatting &amp; Tokenization Friendliness</h2>



<ul class="wp-block-list">
<li><strong>Consistent whitespace-based structure</strong> (Python indentation, standard 4-space blocks) maps cleanly onto token boundaries. Irregular formatting or mixed-indentation legacy code increases noise.</li>



<li><strong>Common delimiters and punctuation.</strong> Braces, parentheses, semicolons used uniformly tokenize predictably; exotic delimiter schemes add risk.</li>
</ul>



<h2 class="wp-block-heading">Testability Surface</h2>



<ul class="wp-block-list">
<li><strong>Small, independently callable units.</strong> A language/ecosystem where you can unit-test a function without bootstrapping a framework gives the model a natural stopping point and makes verification cheap.</li>



<li><strong>Deterministic behavior by default.</strong> No hidden randomness, no wall-clock dependence inside core logic — the model can reason about outputs concretely.</li>
</ul>



<h2 class="wp-block-heading">Practical Takeaways</h2>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Prefer</th><th>Over</th><th>Why</th></tr></thead><tbody><tr><td>Typed signatures</td><td>Untyped / duck-typed params</td><td>Constrains output shape</td></tr><tr><td>Sum types / enums</td><td>Magic integers or strings</td><td>Exhaustiveness enforced</td></tr><tr><td>Explicit imports</td><td>Global namespace</td><td>Clear dependency graph</td></tr><tr><td>Returned errors</td><td>Broad exception swallowing</td><td>Localized failure handling</td></tr><tr><td>Immutable data flow</td><td>Shared mutable state</td><td>Less aliasing to track</td></tr><tr><td>Standard library calls</td><td>Invented helpers</td><td>Matches training frequency</td></tr><tr><td>One canonical idiom</td><td>Five competing styles</td><td>Reduces variance in output</td></tr></tbody></table></figure>



<p class="wp-block-paragraph"><strong>Rule of thumb:</strong> when choosing a language or refactoring a prompt for better one-shot results, pick the option that leaves the <em>fewest implicit decisions</em> to the model. Every explicit choice you encode in the language itself is a decision the model doesn&#8217;t have to guess.</p>



<h1 class="wp-block-heading">Language Competition</h1>



<p class="wp-block-paragraph">Comparing these languages: JavaScript, TypeScript, Lua, Go, Rust, C++, C, ObjC, Haskell, Elm, Python3, Perl, Perl6, PHP8, Vala, Java, Kotlin, Swift, C#, F#.</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Language Feature</th><th>Languages that have it</th><th>Languages that lack it</th></tr></thead><tbody><tr><td>Typed signatures</td><td>TypeScript, Go, Rust, C++, C, ObjC, Haskell, Elm, Perl6, PHP8, Vala, Java, Kotlin, Swift, C#, F#</td><td>JavaScript, Lua, Python3, Perl</td></tr><tr><td>Sum types / enums</td><td>Go, Rust, Haskell, Elm, PHP8, Vala, Java, Kotlin, Swift, C#, F#</td><td>JavaScript, TypeScript, Lua, C++, C, ObjC, Python3, Perl, Perl6, C++</td></tr><tr><td>Optionality made explicit</td><td>Rust (<code>Option&lt;T&gt;</code>), Kotlin (<code>?</code>), Swift (<code>Optional</code>), TypeScript (strict null checks), Java (annotations)</td><td>JavaScript, Lua, C, C++, Python3, Perl, Perl6, PHP8, Go, ObjC</td></tr><tr><td>Uniform function call syntax</td><td>C, C++, Java, Kotlin, Swift, C#, F#, Go, Rust, Haskell, Elm, PHP8, Vala</td><td>JavaScript (optional chaining, spread, template literals), Perl (many sigils), Lua (mixed <code>:</code> and <code>.</code>)</td></tr><tr><td>No hidden mutation in syntax</td><td>Rust (ownership), Haskell (lazy purity), Elm (no side effects), Go (minimal), C (explicit)</td><td>JavaScript (proxies, getters/setters), C++ (operator overloading), Java (properties via beans), PHP8 (magic methods), Swift (computed properties), Kotlin (delegates)</td></tr><tr><td>Single obvious control-flow form</td><td>Go, Rust, C, C++, Java, C#, F#, Kotlin, Swift, Elm, Haskell</td><td>JavaScript (for-of, for-in, forEach, map/filter/reduce), Ruby-like sugar in PHP8, Perl (postfix if/unless)</td></tr><tr><td>Explicit imports</td><td>Go, Rust, ES modules (TS/JS), Java, C#, F#, Kotlin, Swift</td><td>C/C++ (#include is explicit but no module system), Perl (use), Python3 (implicit <strong>init</strong>), PHP8 (autoload), Lua (require), ObjC (@import)</td></tr><tr><td>Flat predictable module paths</td><td>Go, Rust, C, C++</td><td>Java (deep packages), C#/F# (namespaces), Kotlin (packages), Swift (modules + @objc), TS/JS (node_modules resolution)</td></tr><tr><td>Structured errors over exceptions</td><td>Go (error values), Rust (<code>Result&lt;T,E&gt;</code>), C (errno/return codes), Elm (typed Result)</td><td>Java (checked exceptions everywhere), C# (exceptions), Kotlin (exceptions), Swift (throws), C++ (exceptions optional), PHP8 (throw/catch), JS (try/catch only), Python3 (raise/except), Perl (die/warn), Perl6 (exception), ObjC (NSException)</td></tr><tr><td>One idiomatic recovery path</td><td>Rust (<code>?</code> operator), Go (bare error return), C (check errno)</td><td>Java (nested try/catch), C# (multiple catch filters), JS (no standard propagation), Python3 (broad except patterns)</td></tr><tr><td>Default immutability</td><td>Rust (borrow checker), Haskell (values immutable by default), Elm (immutable data)</td><td>JavaScript, TypeScript, Python3, Java, C#, C++, C, Go, PHP8, Perl, Perl6, Lua, Swift (var default), Kotlin (val default helps but var exists), Vala, ObjC</td></tr><tr><td>Pure-function-friendly design</td><td>Haskell, Elm, Rust (functional style encouraged), F#</td><td>C, C++, Java, C#, Objective-C, PHP8, Perl, Perl6, JavaScript, Python3 (mutable defaults common), Go, Kotlin, Swift, Vala, Lua</td></tr><tr><td>Consistent whitespace structure</td><td>Python3 (indentation-based), Go (gofmt enforces), Rust (rustfmt enforces), C (K&amp;R or LLVM style)</td><td>C++ (no enforced formatter), Java (no enforced formatter), C#/F# (formatter varies), Kotlin/Swift (flexible), JS/TS (prettier optional), PHP8 (PSR optional), Perl/Perl6 (freeform), Lua (freeform), ObjC (freeform)</td></tr><tr><td>Common delimiters &amp; punctuation</td><td>C, C++, Java, C#, F#, Kotlin, Swift, Go, Rust, PHP8, Vala</td><td>Python3 (whitespace-delimited, no braces/semicolons), Perl (sigils <code>$@%&amp;*</code>, flexible quoting), Lua (no semicolons, mixed <code>end</code> keywords), Haskell (layout rule, do notation), Elm (indentation-sensitive like Python)</td></tr><tr><td>Small independently callable units</td><td>Go, Rust, C, C++, Python3, Haskell, Elm, Java, C#, F#, Kotlin, Swift</td><td>Perl (monolithic scripts common), PHP8 (procedural legacy), Lua (small ecosystem), ObjC (framework-bound), C++ (template metaprogramming complexity)</td></tr><tr><td>Deterministic behavior by default</td><td>Rust, Haskell, Elm, Go, C, C++</td><td>JavaScript (event-loop timing, floating-point variance), Python3 (dict ordering pre-3.7, hash randomization), PHP8 (locale-dependent sorting), Perl (hash ordering), Java (HashMap iteration order), C# (dictionary enumeration), Kotlin (collection impl choices), Swift (Set unordered), Vala (GLib dict ordering)</td></tr></tbody></table></figure>



<p class="wp-block-paragraph"></p><p>The post <a href="https://riceball.com/2026/09/28/language-characteristics-that-help-llms-write-better-code/">Language Characteristics that Help LLMs Write Better Code</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/09/28/language-characteristics-that-help-llms-write-better-code/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Configuring Regolith to Send Windows to Workspaces (long)</title>
		<link>https://riceball.com/2026/09/17/configuring-regolith-to-send-windows-to-workspaces-long/</link>
					<comments>https://riceball.com/2026/09/17/configuring-regolith-to-send-windows-to-workspaces-long/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Fri, 18 Sep 2026 04:16:25 +0000</pubDate>
				<category><![CDATA[Human Learning]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[MINT]]></category>
		<category><![CDATA[Regolith]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=30526</guid>

					<description><![CDATA[<p>This seemed simple enough, to set up the system to send windows to specific workspaces, and specific screens, but I ended up getting into C preprocessor headaches, and then eventually figured out how to name the workspaces, literally, and had a few problems after that. It&#8217;s not easy, but here&#8217;s what I&#8217;ve done so far, [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/09/17/configuring-regolith-to-send-windows-to-workspaces-long/">Configuring Regolith to Send Windows to Workspaces (long)</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">This seemed simple enough, to set up the system to send windows to specific workspaces, and specific screens, but I ended up getting into C preprocessor headaches, and then eventually figured out how to name the workspaces, literally, and had a few problems after that. It&#8217;s not easy, but here&#8217;s what I&#8217;ve done so far, and how I did it.</p>



<p class="wp-block-paragraph">So, here&#8217;s my current desktop layout. It&#8217;s a  laptop plugged into a HD monitor, for two screens.</p>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="764" height="489" src="https://riceball.com/wp-content/uploads/sites/2/2026/09/Screenshot-from-2026-09-17-19-49-23.png?wsr" alt="" class="wp-image-30528" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/09/Screenshot-from-2026-09-17-19-49-23.png 764w, https://riceball.com/wp-content/uploads/sites/2/2026/09/Screenshot-from-2026-09-17-19-49-23-300x192.png 300w" sizes="(max-width: 764px) 100vw, 764px" /></figure>



<p class="wp-block-paragraph">My system is MINT Linux Cinnamon, but with Regolith, a GNOME environment with the i3 full-screen/tiling window manager. Here&#8217;s a video about it:</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="Regolith Linux - Ubuntu with i3 Tiling Window Manager" width="500" height="281" src="https://www.youtube.com/embed/3x1CR5Q2rrY?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p class="wp-block-paragraph">i3 uses <strong>named workspaces</strong> (also known as Desktops, Virtual Desktops, or Spaces in Windows and MacOS), numbered from 1 to 19, and you jump to them by pressing Win+1, Win+2&#8230; Win+Ctrl+1&#8230; etc. (Win can also be the Apple Key or &#8220;Super&#8221;)</p>



<p class="wp-block-paragraph">Normally, you have to press Win+Shift+1 to move a window to workspace 1.</p>



<p class="wp-block-paragraph">Starting up a session can be a pain, because  you bring up the apps you want, and they all show up in the current workspaces.</p>



<p class="wp-block-paragraph">I like to keep all my comms apps, like Signal, in workspace 1. I want my first browser to go to workspace 3.</p>



<p class="wp-block-paragraph">I also want all my odd-numbered workspaces on the big screen on the left, and even numbered workspace on the right, on the laptop screen.</p>



<p class="wp-block-paragraph">Here&#8217;s my config file: .config/regolith3/i3/config.d/workspace-to-display.config</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly># mkdir -p  ~/.config/regolith3/i3/config.d
# vi ~/.config/regolith3/i3/config.d/workspace-to-display.config 
# Run xrandr --listmonitors to get the monitor names
#
# Sample output:
#
# Monitors: 2
# 0: +*HDMI-1 1920/509x1080/286+0+0  HDMI-1
# 1: +eDP-1 1920/309x1080/173+1920+0  eDP-1
#
# Paste the configs below in and edit to match your desired monitor setup

workspace "$ws1" output HDMI-1
workspace "$ws2" output eDP-1
workspace "$ws3" output HDMI-1
workspace "$ws4" output eDP-1
workspace "$ws5" output HDMI-1
workspace "$ws6" output eDP-1
workspace "$ws7" output HDMI-1
workspace "$ws8" output eDP-1
workspace "$ws9" output HDMI-1
workspace "$ws10" output eDP-1
workspace "$ws11" output HDMI-1
workspace "$ws12" output eDP-1
workspace "$ws13" output HDMI-1
workspace "$ws14" output eDP-1
workspace "$ws15" output HDMI-1
workspace "$ws16" output eDP-1
workspace "$ws17" output HDMI-1
workspace "$ws18" output eDP-1
workspace "$ws19" output HDMI-1

assign &#91;class="thunderbird"&#93; "$ws1"
assign &#91;class="proton-mail"&#93; "$ws1"
for_window &#91;class="Signal"&#93; move to workspace "$ws1"
# These don"t work
for_window &#91;class="Element *"&#93; move to workspace "$ws1"
for_window &#91;class="WhatsApp"&#93; move to workspace "$ws1"

assign &#91;class="firefox"&#93; "$ws3"</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4"># mkdir -p  ~/.config/regolith3/i3/config.d</span></span>
<span class="line"><span style="color: #D4D4D4"># vi ~/.config/regolith3/i3/config.d/workspace-to-display.config </span></span>
<span class="line"><span style="color: #D4D4D4"># Run xrandr --listmonitors to get the monitor names</span></span>
<span class="line"><span style="color: #D4D4D4">#</span></span>
<span class="line"><span style="color: #D4D4D4"># Sample output:</span></span>
<span class="line"><span style="color: #D4D4D4">#</span></span>
<span class="line"><span style="color: #D4D4D4"># Monitors: 2</span></span>
<span class="line"><span style="color: #D4D4D4"># 0: +*HDMI-1 1920/509x1080/286+0+0  HDMI-1</span></span>
<span class="line"><span style="color: #D4D4D4"># 1: +eDP-1 1920/309x1080/173+1920+0  eDP-1</span></span>
<span class="line"><span style="color: #D4D4D4">#</span></span>
<span class="line"><span style="color: #D4D4D4"># Paste the configs below in and edit to match your desired monitor setup</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws1&quot; output HDMI-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws2&quot; output eDP-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws3&quot; output HDMI-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws4&quot; output eDP-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws5&quot; output HDMI-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws6&quot; output eDP-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws7&quot; output HDMI-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws8&quot; output eDP-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws9&quot; output HDMI-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws10&quot; output eDP-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws11&quot; output HDMI-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws12&quot; output eDP-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws13&quot; output HDMI-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws14&quot; output eDP-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws15&quot; output HDMI-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws16&quot; output eDP-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws17&quot; output HDMI-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws18&quot; output eDP-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws19&quot; output HDMI-1</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">assign &#91;class=&quot;thunderbird&quot;&#93; &quot;$ws1&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">assign &#91;class=&quot;proton-mail&quot;&#93; &quot;$ws1&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">for_window &#91;class=&quot;Signal&quot;&#93; move to workspace &quot;$ws1&quot;</span></span>
<span class="line"><span style="color: #D4D4D4"># These don&quot;t work</span></span>
<span class="line"><span style="color: #D4D4D4">for_window &#91;class=&quot;Element *&quot;&#93; move to workspace &quot;$ws1&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">for_window &#91;class=&quot;WhatsApp&quot;&#93; move to workspace &quot;$ws1&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">assign &#91;class=&quot;firefox&quot;&#93; &quot;$ws3&quot;</span></span></code></pre></div>



<h2 class="wp-block-heading">Workspaces Associated with Displays</h2>



<p class="wp-block-paragraph">At the top of my config, I have some comments to remind me how I did it. You run xrandr &#8211;listmonitors to get the monitor names:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>xrandr --listmonitors</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">xrandr --listmonitors</span></span></code></pre></div>



<p class="wp-block-paragraph">Then you put these lines to assign a workspace to a display:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>workspace "$ws1" output HDMI-1
workspace "$ws2" output eDP-1
.
.
.
workspace "$ws18" output eDP-1
workspace "$ws19" output HDMI-1</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">workspace &quot;$ws1&quot; output HDMI-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws2&quot; output eDP-1</span></span>
<span class="line"><span style="color: #D4D4D4">.</span></span>
<span class="line"><span style="color: #D4D4D4">.</span></span>
<span class="line"><span style="color: #D4D4D4">.</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws18&quot; output eDP-1</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws19&quot; output HDMI-1</span></span></code></pre></div>



<p class="wp-block-paragraph">Then, you assign windows to workspaces:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>assign &#91;class="thunderbird"&#93; "$ws1"
assign &#91;class="proton-mail"&#93; "$ws1"
for_window &#91;class="Signal"&#93; move to workspace "$ws1"
# These don"t work
for_window &#91;class="Element *"&#93; move to workspace "$ws1"
for_window &#91;class="WhatsApp"&#93; move to workspace "$ws1"

assign &#91;class="firefox"&#93; "$ws3"</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">assign &#91;class=&quot;thunderbird&quot;&#93; &quot;$ws1&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">assign &#91;class=&quot;proton-mail&quot;&#93; &quot;$ws1&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">for_window &#91;class=&quot;Signal&quot;&#93; move to workspace &quot;$ws1&quot;</span></span>
<span class="line"><span style="color: #D4D4D4"># These don&quot;t work</span></span>
<span class="line"><span style="color: #D4D4D4">for_window &#91;class=&quot;Element *&quot;&#93; move to workspace &quot;$ws1&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">for_window &#91;class=&quot;WhatsApp&quot;&#93; move to workspace &quot;$ws1&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">assign &#91;class=&quot;firefox&quot;&#93; &quot;$ws3&quot;</span></span></code></pre></div>



<p class="wp-block-paragraph">The first three lines work, and the last line works, but the lines for Element and WhatsApp don&#8217;t work. These config lines are tricky to figure out, because you don&#8217;t know what info the app is exposing to the window manager. Finding out is a pain in the butt, but here are instructions:</p>



<p class="wp-block-paragraph"><a href="https://stackoverflow.com/questions/65049414/in-i3wm-how-can-i-open-programs-on-another-workspace-at-startup">https://stackoverflow.com/questions/65049414/in-i3wm-how-can-i-open-programs-on-another-workspace-at-startup</a></p>



<p class="wp-block-paragraph">One of these days, I may update this with a bunch of programs configured to show up on specific workspaces.</p>



<h2 class="wp-block-heading">Errors</h2>



<p class="wp-block-paragraph">For a while, I had my own config in .config/regolith3/i3/config, which I think may have caused error messages and weird behavior. (I may be wrong, though.)</p>



<p class="wp-block-paragraph">The workspace names were causing problems. The &#8220;names&#8221; looked like HTML &#8211; because they were:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-Deja-Vu-Mono.ttf" style="font-size:.875rem;font-family:Code-Pro-Deja-Vu-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>1:&lt;span> &lt;/span>1 &lt;span foreground="#3584E4">&lt;/span>&lt;span> &lt;/span></textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">1:&lt;span&gt; &lt;/span&gt;1 &lt;span foreground=&quot;#3584E4&quot;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span></code></pre></div>



<p class="wp-block-paragraph">That&#8217;s the name, with all the HTML in it. It gets rendered by Pango.</p>



<p class="wp-block-paragraph">However, when this line is expanded, it breaks:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-Deja-Vu-Mono.ttf" style="font-size:.875rem;font-family:Code-Pro-Deja-Vu-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly># The original config line:
workspace "$ws1" output HDMI-1
# The line after the variable expansion:
workspace "1:&lt;span> &lt;/span>1 &lt;span foreground="#3584E4">&lt;/span>&lt;span> &lt;/span>" output HDMI-1</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4"># The original config line:</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;$ws1&quot; output HDMI-1</span></span>
<span class="line"><span style="color: #D4D4D4"># The line after the variable expansion:</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &quot;1:&lt;span&gt; &lt;/span&gt;1 &lt;span foreground=&quot;#3584E4&quot;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&quot; output HDMI-1</span></span></code></pre></div>



<p class="wp-block-paragraph">The problem is the double quote within the double-quoted string. I got a ton of error messages.</p>



<p class="wp-block-paragraph">I thought, &#8220;this is easy. Try using single-quotes&#8221;:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-Deja-Vu-Mono.ttf" style="font-size:.875rem;font-family:Code-Pro-Deja-Vu-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly># The original config line:
workspace '$ws1' output HDMI-1
# The line after the variable expansion:
workspace '1:&lt;span> &lt;/span>1 &lt;span foreground='#3584E4'>&lt;/span>&lt;span> &lt;/span>' output HDMI-1</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4"># The original config line:</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &#39;$ws1&#39; output HDMI-1</span></span>
<span class="line"><span style="color: #D4D4D4"># The line after the variable expansion:</span></span>
<span class="line"><span style="color: #D4D4D4">workspace &#39;1:&lt;span&gt; &lt;/span&gt;1 &lt;span foreground=&#39;#3584E4&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&#39; output HDMI-1</span></span></code></pre></div>



<p class="wp-block-paragraph">OK, I don&#8217;t know what the hell was going on, but single quotes caused the variable expansion to also use <strong>single quotes</strong> inside the string.</p>



<p class="wp-block-paragraph">I tried it without any quotes at all, but that didn&#8217;t work, because variable expansions are done before the entire line is parsed. So all the spaces in the code would separate the name into words. That&#8217;s why the quotes were there.</p>



<p class="wp-block-paragraph">After reading a lot, and digging around, I found where these long, troublesome names were being generated: /usr/share/regolith-look/default/wm</p>



<p class="wp-block-paragraph">The code looks a little like this:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-Deja-Vu-Mono.ttf" style="font-size:.875rem;font-family:Code-Pro-Deja-Vu-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#define Q(x) #x
#define QUOTE(x) Q(x)
#define glyph typeface_bar_glyph_workspace
#define WORKSPACE_NAME(INDEX, COLOR, GLYPH) INDEX:&lt;span> &lt;/span>INDEX &lt;span foreground=COLOR>GLYPH&lt;/span>&lt;span> &lt;/span>

wm.workspace.01.name: WORKSPACE_NAME(1, QUOTE(color_blue), glyph)
.
.
.</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">#define Q(x) #x</span></span>
<span class="line"><span style="color: #D4D4D4">#define QUOTE(x) Q(x)</span></span>
<span class="line"><span style="color: #D4D4D4">#define glyph typeface_bar_glyph_workspace</span></span>
<span class="line"><span style="color: #D4D4D4">#define WORKSPACE_NAME(INDEX, COLOR, GLYPH) INDEX:&lt;span&gt; &lt;/span&gt;INDEX &lt;span foreground=COLOR&gt;GLYPH&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.01.name: WORKSPACE_NAME(1, QUOTE(color_blue), glyph)</span></span>
<span class="line"><span style="color: #D4D4D4">.</span></span>
<span class="line"><span style="color: #D4D4D4">.</span></span>
<span class="line"><span style="color: #D4D4D4">.</span></span></code></pre></div>



<p class="wp-block-paragraph">Yes, those are C preprocessor (cpp) directives.</p>



<p class="wp-block-paragraph">For the 99% of people who don&#8217;t know what C or the C Preprocessor is: it&#8217;s a macro language. Here&#8217;s a video about it. Skip it if you know it.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="#30: Preprocesor and Macros | C Programming for Beginners" width="500" height="281" src="https://www.youtube.com/embed/cmGq62c1Ceg?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p class="wp-block-paragraph">The obvious fix was to single-quote the color value, so the expansion would look like this:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-Deja-Vu-Mono.ttf" style="font-size:.875rem;font-family:Code-Pro-Deja-Vu-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>workspace "1:&lt;span> &lt;/span>1 &lt;span foreground='#3584E4'>&lt;/span>&lt;span> &lt;/span>" output HDMI-1</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">workspace &quot;1:&lt;span&gt; &lt;/span&gt;1 &lt;span foreground=&#39;#3584E4&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&quot; output HDMI-1</span></span></code></pre></div>



<p class="wp-block-paragraph">I tried:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-Deja-Vu-Mono.ttf" style="font-size:.875rem;font-family:Code-Pro-Deja-Vu-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#define SQ(X) 'X'</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">#define SQ(X) &#39;X&#39;</span></span></code></pre></div>



<p class="wp-block-paragraph">That didn&#8217;t work, because the X <strong>would not expand within a single (or double) quoted string.</strong> (This was one of the features of the cpp.)</p>



<p class="wp-block-paragraph">After an hour or two of reading, talking to AI, and looking for solutions, and failing to ever get it working with macros, I figured out something: I needed to run the cpp on the config files to get the computed config, because the workspace name definitions would be in there.</p>



<p class="wp-block-paragraph">The file at the top of all the configs, with all the #includes, was called root, and the command to spit out the config: </p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-Deja-Vu-Mono.ttf" style="font-size:.875rem;font-family:Code-Pro-Deja-Vu-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>cpp /usr/share/regolith-look/default/root</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">cpp /usr/share/regolith-look/default/root</span></span></code></pre></div>



<p class="wp-block-paragraph">That showed me the computed config:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-Deja-Vu-Mono.ttf" style="font-size:.875rem;font-family:Code-Pro-Deja-Vu-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>wm.workspace.01.name: 1:&lt;span> &lt;/span>1 &lt;span foreground="#3584E4">&lt;/span>&lt;span> &lt;/span>
wm.workspace.02.name: 2:&lt;span> &lt;/span>2 &lt;span foreground="#95E6CB">&lt;/span>&lt;span> &lt;/span>
wm.workspace.03.name: 3:&lt;span> &lt;/span>3 &lt;span foreground="#33D17A">&lt;/span>&lt;span> &lt;/span>
.
.
.</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">wm.workspace.01.name: 1:&lt;span&gt; &lt;/span&gt;1 &lt;span foreground=&quot;#3584E4&quot;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.02.name: 2:&lt;span&gt; &lt;/span&gt;2 &lt;span foreground=&quot;#95E6CB&quot;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.03.name: 3:&lt;span&gt; &lt;/span&gt;3 &lt;span foreground=&quot;#33D17A&quot;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">.</span></span>
<span class="line"><span style="color: #D4D4D4">.</span></span>
<span class="line"><span style="color: #D4D4D4">.</span></span></code></pre></div>



<p class="wp-block-paragraph">Now, we just need to be able to override what the macros produced.</p>



<p class="wp-block-paragraph">This can be done through Xresources.</p>



<p class="wp-block-paragraph">Here are the config lines that define the $ws1&#8230; variables:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-Deja-Vu-Mono.ttf" style="font-size:.875rem;font-family:Code-Pro-Deja-Vu-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>###############################################################################
# Workspace Names
# These are the labels which define each workspace.
###############################################################################

set_from_resource $ws1  wm.workspace.01.name "1"
set_from_resource $ws2  wm.workspace.02.name "2"
set_from_resource $ws3  wm.workspace.03.name "3"
.
.
.</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">###############################################################################</span></span>
<span class="line"><span style="color: #D4D4D4"># Workspace Names</span></span>
<span class="line"><span style="color: #D4D4D4"># These are the labels which define each workspace.</span></span>
<span class="line"><span style="color: #D4D4D4">###############################################################################</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">set_from_resource $ws1  wm.workspace.01.name &quot;1&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">set_from_resource $ws2  wm.workspace.02.name &quot;2&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">set_from_resource $ws3  wm.workspace.03.name &quot;3&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">.</span></span>
<span class="line"><span style="color: #D4D4D4">.</span></span>
<span class="line"><span style="color: #D4D4D4">.</span></span></code></pre></div>



<p class="wp-block-paragraph">set_from_resource sets a variable value, first looking for the value in Xresources, and if it&#8217;s not there, using the supplied default.</p>



<p class="wp-block-paragraph">The canonical way for end  users to configure Regolith is through the Xresources file.  (Having now tried to mess with the config files, I understand why: it&#8217;s easy to completely screw up the config files.)</p>



<p class="wp-block-paragraph">So setting the correct value was as simple as pasting this into the .config/regolith3/Xresources file:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-Deja-Vu-Mono.ttf" style="font-size:.875rem;font-family:Code-Pro-Deja-Vu-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>wm.workspace.01.name: 1:&lt;span> &lt;/span>1 &lt;span foreground='#3584E4'>&lt;/span>&lt;span> &lt;/span>
wm.workspace.02.name: 2:&lt;span> &lt;/span>2 &lt;span foreground='#95E6CB'>&lt;/span>&lt;span> &lt;/span>
wm.workspace.03.name: 3:&lt;span> &lt;/span>3 &lt;span foreground='#33D17A'>&lt;/span>&lt;span> &lt;/span>
wm.workspace.04.name: 4:&lt;span> &lt;/span>4 &lt;span foreground='#F6D32D'>&lt;/span>&lt;span> &lt;/span>
wm.workspace.05.name: 5:&lt;span> &lt;/span>5 &lt;span foreground='#FF7800'>&lt;/span>&lt;span> &lt;/span>
wm.workspace.06.name: 6:&lt;span> &lt;/span>6 &lt;span foreground='#E01B24'>&lt;/span>&lt;span> &lt;/span>
wm.workspace.07.name: 7:&lt;span> &lt;/span>7 &lt;span foreground='#75507B'>&lt;/span>&lt;span> &lt;/span>
wm.workspace.08.name: 8:&lt;span> &lt;/span>8 &lt;span foreground='#9141AC'>&lt;/span>&lt;span> &lt;/span>
wm.workspace.09.name: 9:&lt;span> &lt;/span>9 &lt;span foreground='#986A44'>&lt;/span>&lt;span> &lt;/span>
wm.workspace.10.name: 10:&lt;span> &lt;/span>10 &lt;span foreground='#3584E4'>&lt;/span>&lt;span> &lt;/span>
wm.workspace.11.name: 11:&lt;span> &lt;/span>11 &lt;span foreground='#95E6CB'>&lt;/span>&lt;span> &lt;/span>
wm.workspace.12.name: 12:&lt;span> &lt;/span>12 &lt;span foreground='#33D17A'>&lt;/span>&lt;span> &lt;/span>
wm.workspace.13.name: 13:&lt;span> &lt;/span>13 &lt;span foreground='#F6D32D'>&lt;/span>&lt;span> &lt;/span>
wm.workspace.14.name: 14:&lt;span> &lt;/span>14 &lt;span foreground='#FF7800'>&lt;/span>&lt;span> &lt;/span>
wm.workspace.15.name: 15:&lt;span> &lt;/span>15 &lt;span foreground='#E01B24'>&lt;/span>&lt;span> &lt;/span>
wm.workspace.16.name: 16:&lt;span> &lt;/span>16 &lt;span foreground='#75507B'>&lt;/span>&lt;span> &lt;/span>
wm.workspace.17.name: 17:&lt;span> &lt;/span>17 &lt;span foreground='#9141AC'>&lt;/span>&lt;span> &lt;/span>
wm.workspace.18.name: 18:&lt;span> &lt;/span>18 &lt;span foreground='#986A44'>&lt;/span>&lt;span> &lt;/span>
wm.workspace.19.name: 19:&lt;span> &lt;/span>19 &lt;span foreground='#3584E4'>&lt;/span>&lt;span> &lt;/span></textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">wm.workspace.01.name: 1:&lt;span&gt; &lt;/span&gt;1 &lt;span foreground=&#39;#3584E4&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.02.name: 2:&lt;span&gt; &lt;/span&gt;2 &lt;span foreground=&#39;#95E6CB&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.03.name: 3:&lt;span&gt; &lt;/span&gt;3 &lt;span foreground=&#39;#33D17A&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.04.name: 4:&lt;span&gt; &lt;/span&gt;4 &lt;span foreground=&#39;#F6D32D&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.05.name: 5:&lt;span&gt; &lt;/span&gt;5 &lt;span foreground=&#39;#FF7800&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.06.name: 6:&lt;span&gt; &lt;/span&gt;6 &lt;span foreground=&#39;#E01B24&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.07.name: 7:&lt;span&gt; &lt;/span&gt;7 &lt;span foreground=&#39;#75507B&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.08.name: 8:&lt;span&gt; &lt;/span&gt;8 &lt;span foreground=&#39;#9141AC&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.09.name: 9:&lt;span&gt; &lt;/span&gt;9 &lt;span foreground=&#39;#986A44&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.10.name: 10:&lt;span&gt; &lt;/span&gt;10 &lt;span foreground=&#39;#3584E4&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.11.name: 11:&lt;span&gt; &lt;/span&gt;11 &lt;span foreground=&#39;#95E6CB&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.12.name: 12:&lt;span&gt; &lt;/span&gt;12 &lt;span foreground=&#39;#33D17A&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.13.name: 13:&lt;span&gt; &lt;/span&gt;13 &lt;span foreground=&#39;#F6D32D&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.14.name: 14:&lt;span&gt; &lt;/span&gt;14 &lt;span foreground=&#39;#FF7800&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.15.name: 15:&lt;span&gt; &lt;/span&gt;15 &lt;span foreground=&#39;#E01B24&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.16.name: 16:&lt;span&gt; &lt;/span&gt;16 &lt;span foreground=&#39;#75507B&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.17.name: 17:&lt;span&gt; &lt;/span&gt;17 &lt;span foreground=&#39;#9141AC&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.18.name: 18:&lt;span&gt; &lt;/span&gt;18 &lt;span foreground=&#39;#986A44&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">wm.workspace.19.name: 19:&lt;span&gt; &lt;/span&gt;19 &lt;span foreground=&#39;#3584E4&#39;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;</span></span></code></pre></div>



<p class="wp-block-paragraph">NOTE: the color values are single quoted. I copied this from the config dump above, and did a search-replace for &#8220;, replacing with &#8216;.</p>



<p class="wp-block-paragraph">That corrected the config file errors I was getting, and a few other problems I may have introduced.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p class="wp-block-paragraph">This was way more difficult than it needed to be.</p>



<p class="wp-block-paragraph">This workspace naming scheme seems like a bad idea, at least if the name is more than a single word. Rather than referring to a workspace by it&#8217;s fancy HTML code label, a named workspace should also have a &#8220;label&#8221; property, for this string to display.</p>



<p class="wp-block-paragraph">The cpp is kind of cool, but kind of a pain in the ass.</p>



<p class="wp-block-paragraph"></p><p>The post <a href="https://riceball.com/2026/09/17/configuring-regolith-to-send-windows-to-workspaces-long/">Configuring Regolith to Send Windows to Workspaces (long)</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/09/17/configuring-regolith-to-send-windows-to-workspaces-long/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Markdown Editors</title>
		<link>https://riceball.com/2026/09/11/markdown-editors/</link>
					<comments>https://riceball.com/2026/09/11/markdown-editors/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Fri, 11 Sep 2026 21:30:21 +0000</pubDate>
				<category><![CDATA[Human Learning]]></category>
		<category><![CDATA[Zsh]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=30488</guid>

					<description><![CDATA[<p>Someone asked me what markdown editors are good. I had to do some research, because I mainly used vim and one of the .rst viewers for a while. Then I switched to CryptPad for a minute, and then to Obsidian. Recommendations at the bottom. DIY GNOME Environment Markdown Editor This is a script that makes [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/09/11/markdown-editors/">Markdown Editors</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">Someone asked me what markdown editors are good. I had to do some research, because I mainly used vim and one of the .rst viewers for a while. Then I switched to CryptPad for a minute, and then to Obsidian. Recommendations at the bottom.</p>



<h2 class="wp-block-heading">DIY GNOME Environment Markdown Editor</h2>



<p class="wp-block-paragraph">This is a script that makes a simple &#8220;Markdown editor&#8221; that&#8217;s a gedit window, and a <a href="https://github.com/commenthol/md-fileserver">md-fileserver</a> program, that, together, work like editors like Apostrophe.</p>



<p class="wp-block-paragraph">One window is for editing.</p>



<p class="wp-block-paragraph">The other is a preview.</p>



<p class="wp-block-paragraph">Save it into md-edit, and do a <code>chmod u+x md-edit</code> to make it an executable command. Note that it uses zsh, not bash, so you need zsh installed.</p>



<p class="wp-block-paragraph">This program automatically creates a document in &#8220;MarkdownNotes&#8221;, so I can create notes without naming the file. I realize this isn&#8217;t everyone&#8217;s use case, and I&#8217;m just presenting this as an example.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#! /usr/bin/zsh

# Markdown editor setup using md-fileserver

if [&#91; -z "$1" &#93;]; then
    F="Untitled-`date +%Y-%m-%d`-$RANDOM.md"
    mkdir -p ~/Documents/MarkdownNotes
    cd ~/Documents/MarkdownNotes
else
    F="$1"
fi

touch "$F"

gedit "$F" &amp;

echo 
echo Uses: https://github.com/commenthol/md-fileserver
echo 
echo URL to view the doc
echo
echo http://localhost:4000/`pwd`/$F
echo
echo http://localhost:4000/`pwd`/
echo
echo Settings
echo
echo http://localhost:4000/config
echo
echo Confluencer docs: https://www.npmjs.com/package/confluencer
echo
mdstart -c "$F"</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">#! /usr/bin/zsh</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Markdown editor setup using md-fileserver</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [&#91; -z </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$1</span><span style="color: #CE9178">&quot;</span><span style="color: #D4D4D4"> &#93;]; </span><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">F</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;Untitled-`</span><span style="color: #DCDCAA">date</span><span style="color: #CE9178"> +%Y-%m-%d`-</span><span style="color: #9CDCFE">$RANDOM</span><span style="color: #CE9178">.md&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">mkdir</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-p</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">~/Documents/MarkdownNotes</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">cd</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">~/Documents/MarkdownNotes</span></span>
<span class="line"><span style="color: #C586C0">else</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">F</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$1</span><span style="color: #CE9178">&quot;</span></span>
<span class="line"><span style="color: #C586C0">fi</span></span>
<span class="line"></span>
<span class="line"><span style="color: #DCDCAA">touch</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$F</span><span style="color: #CE9178">&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #DCDCAA">gedit</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$F</span><span style="color: #CE9178">&quot;</span><span style="color: #D4D4D4"> &amp;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Uses:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">https://github.com/commenthol/md-fileserver</span></span>
<span class="line"><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">URL</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">to</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">view</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">the</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">doc</span></span>
<span class="line"><span style="color: #DCDCAA">echo</span></span>
<span class="line"><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">http://localhost:4000/`</span><span style="color: #DCDCAA">pwd</span><span style="color: #CE9178">`</span><span style="color: #DCDCAA">/$F</span></span>
<span class="line"><span style="color: #DCDCAA">echo</span></span>
<span class="line"><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">http://localhost:4000/`</span><span style="color: #DCDCAA">pwd</span><span style="color: #CE9178">`</span><span style="color: #DCDCAA">/</span></span>
<span class="line"><span style="color: #DCDCAA">echo</span></span>
<span class="line"><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Settings</span></span>
<span class="line"><span style="color: #DCDCAA">echo</span></span>
<span class="line"><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">http://localhost:4000/config</span></span>
<span class="line"><span style="color: #DCDCAA">echo</span></span>
<span class="line"><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Confluencer</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">docs:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">https://www.npmjs.com/package/confluencer</span></span>
<span class="line"><span style="color: #DCDCAA">echo</span></span>
<span class="line"><span style="color: #DCDCAA">mdstart</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-c</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$F</span><span style="color: #CE9178">&quot;</span></span></code></pre></div>



<h2 class="wp-block-heading">I wrote this post in md-edit</h2>



<p class="wp-block-paragraph">You can usually copy-paste Markdown into WordPress, and it&#8217;ll automatically format it the same way. gedit is way faster than the WordPress block editor.</p>



<h1 class="wp-block-heading">Other Markdown Editors I like</h1>



<p class="wp-block-paragraph"><a href="https://obsidian.md/">Obsidian</a> &#8211; the best editor, is also a note-taker, outliner, and knowledge graph editor. Has great renaming UI (you can&#8217;t tell it&#8217;s there). An awesome tool for writing your LLM files.</p>



<p class="wp-block-paragraph"><a href="https://apps.gnome.org/Apostrophe/">Apostrophe</a> &#8211; the slickest one. A &#8220;no distraction&#8221; editor.</p>



<p class="wp-block-paragraph"><a href="https://cryptpad.fr/code/">Cryptpad.fr/code</a>&#8216;s code editor. A nice, no-install, encrypted solution.</p><p>The post <a href="https://riceball.com/2026/09/11/markdown-editors/">Markdown Editors</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/09/11/markdown-editors/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Learning Elm: LLMs</title>
		<link>https://riceball.com/2026/09/10/learning-elm-llms/</link>
					<comments>https://riceball.com/2026/09/10/learning-elm-llms/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Fri, 11 Sep 2026 05:40:48 +0000</pubDate>
				<category><![CDATA[Human Learning]]></category>
		<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[Elm]]></category>
		<category><![CDATA[Thaura]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=30485</guid>

					<description><![CDATA[<p>I&#8217;ve been messing with some LLMs to write Elm code. So far, so-so. I haven&#8217;t done a thorough test, mainly because I&#8217;m still learning Elm, but some LLMs seem to do great with Elm code, and some seem to run endless loops of debugging failures. I&#8217;ve been playing with Nemotron, Muse Spark, MiMo, and Thaura [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/09/10/learning-elm-llms/">Learning Elm: LLMs</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">I&#8217;ve been messing with some LLMs to write Elm code. So far, so-so.</p>



<p class="wp-block-paragraph">I haven&#8217;t done a thorough test, mainly because I&#8217;m still learning Elm, but some LLMs seem to do great with Elm code, and some seem to run endless loops of debugging failures. I&#8217;ve been playing with Nemotron, Muse Spark, MiMo, and Thaura Work.</p>



<p class="wp-block-paragraph">The debugging cycles are <strong>super nice</strong>. When things are working well,<strong> the code generated compiles the first time, or after one or two cycles through the compiler</strong>.</p>



<p class="wp-block-paragraph">One time, I asked to replicate the layout of an Indymedia site, and gave a brief description of what it was, and what parts I wanted. It cranked out the code quickly, and it compiled, and it looked nice.</p>



<p class="wp-block-paragraph">Even more important: it was under 100 lines of Html library code. The CSS was a bit longer.</p>



<p class="wp-block-paragraph">Thaura advised using <a href="https://elm-pages.com">https://elm-pages.com</a>, and at least one LLM produced code that compiled.</p>



<p class="wp-block-paragraph"></p><p>The post <a href="https://riceball.com/2026/09/10/learning-elm-llms/">Learning Elm: LLMs</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/09/10/learning-elm-llms/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Thaura: Writing with an LLM</title>
		<link>https://riceball.com/2026/09/06/thaura-writing-with-an-llm/</link>
					<comments>https://riceball.com/2026/09/06/thaura-writing-with-an-llm/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sun, 06 Sep 2026 21:43:46 +0000</pubDate>
				<category><![CDATA[Human Learning]]></category>
		<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[Thaura]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=30471</guid>

					<description><![CDATA[<p>More and more people are using LLMs to write their documents: lawyers are using LLMs to write arguments full of bogus references; college students are submitting papers that make false claims. LLMs are amazing, but they also hallucinate. People who skip the thinking get burned. I don&#8217;t use the LLM to write my documents; I [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/09/06/thaura-writing-with-an-llm/">Thaura: Writing with an LLM</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">More and more people are using LLMs to write their documents: lawyers are using LLMs to write arguments full of bogus references; college students are submitting papers that make false claims.</p>



<p class="wp-block-paragraph">LLMs are amazing, but they also hallucinate. People who skip the thinking get burned.</p>



<p class="wp-block-paragraph">I don&#8217;t use the LLM to write my documents; I use it to critique them.</p>



<p class="wp-block-paragraph">Generating a critique is as simple as pasting your text into the chat and asking for a critique. Example:</p>


<pre class="wp-block-code has-d-4-d-4-d-4-color has-text-color has-875-rem-font-size"><span><code class="hljs language-plaintext">A critique of this: &lt;paste text here&gt;</code></span></pre>


<p class="wp-block-paragraph">Then I read the critique and rewrote; I repeat the loop if necessary.</p>



<h2 class="wp-block-heading">Setting Up a Reusable Editor</h2>



<p class="wp-block-paragraph">Over time, my prompt got more complex, with more instructions. I wanted the spelling fixed, but the grammar and style critiqued without changing the text. I wanted my logical fallacies pointed out. The prompt was getting unmanageable.</p>



<p class="wp-block-paragraph">I&#8217;m using Thaura.ai, which has a feature called <strong>Projects</strong> that lets you save prompts for a recurring task.</p>



<p class="wp-block-paragraph">My first editor project used this prompt:</p>


<pre class="wp-block-code has-d-4-d-4-d-4-color has-text-color has-875-rem-font-size"><span><code class="hljs language-plaintext shcb-wrap-lines">Extremely critical editor looks for all kinds of flaws, particularly flaws of logic, the regular list of logical fallacies, unusual or unconventional definitions, grammar errors, florid language, passive voice, failures to acknowledge limitations, ahistoricism, errors of fact, spelling errors, references to controversial sources, references to low quality sources, profanity, race stereotype, gender stereotyping, homophobia, insensitivity to issues of economic or social class, rudeness insolence.</code></span></pre>


<p class="wp-block-paragraph">That prompt caught plenty, but I wanted consistent scoring, so I added a <strong>system prompt</strong> to calculate a score for each flaw, plus an overall document score. The per-flaw scores told me what to fix first; the overall score gave me a number to compare against after each rewrite:</p>


<pre class="wp-block-code has-d-4-d-4-d-4-color has-text-color has-875-rem-font-size"><span><code class="hljs language-plaintext shcb-wrap-lines">Reply listing each flaw, with a brief explanation, and a severity score of 1 to 3, higher is worse. Calculate an aggregate score of 0 to 100, using some kind of quadratic function, and advise on publishing the text.</code></span></pre>


<p class="wp-block-paragraph">The criticisms were often harsh, but they forced me to actually defend what I&#8217;d written, and the drafts got better for it.</p>



<p class="wp-block-paragraph">Sometimes, the critique I got was brief, but even then, I forced myself to re-read the text and rework it. Doing a rewrite of a first draft usually improved it, but occasionally, reviewing my own work made me reconsider whether to publish it at all.</p>



<p class="wp-block-paragraph">The whole loop is fast: paste, read the critique, revise. You don&#8217;t need to agree with every point — the value is in being forced to re-read your own words.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">(This post was written with an editing assistant, which I&#8217;ll describe in a future post.)</p><p>The post <a href="https://riceball.com/2026/09/06/thaura-writing-with-an-llm/">Thaura: Writing with an LLM</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/09/06/thaura-writing-with-an-llm/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Learning Elm: pipe tricks</title>
		<link>https://riceball.com/2026/09/03/learning-elm-pipe-tricks/</link>
					<comments>https://riceball.com/2026/09/03/learning-elm-pipe-tricks/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Fri, 04 Sep 2026 05:23:31 +0000</pubDate>
				<category><![CDATA[Human Learning]]></category>
		<category><![CDATA[Elm]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=30413</guid>

					<description><![CDATA[<p>https://github.com/elm/compiler/tree/main/hints I found much of the content for this article at: https://sporto.gitbooks.io/elm-tutorial/content/en/01-foundations/02-functions.html Here&#8217;s now to create a learning environment where you can edit a file full of Elm code, and play with the code. Add the &#8220;.&#8221; directory to elm.json. This will tell Elm to search for modules in there: Next up, make the file [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/09/03/learning-elm-pipe-tricks/">Learning Elm: pipe tricks</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph"><a href="https://github.com/elm/compiler/tree/main/hints">https://github.com/elm/compiler/tree/main/hints</a></p>



<p class="wp-block-paragraph">I found much of the content for this article at: <a href="https://sporto.gitbooks.io/elm-tutorial/content/en/01-foundations/02-functions.html">https://sporto.gitbooks.io/elm-tutorial/content/en/01-foundations/02-functions.html</a></p>



<p class="wp-block-paragraph">Here&#8217;s now to create a learning environment where you can edit a file full of Elm code, and play with the code.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly># make a directory and turn it into an Elm project
mkdir elm
cd elm
elm init

# fire up an editor
gedit &amp;

# open up an elm console
elm repl</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955"># make a directory and turn it into an Elm project</span></span>
<span class="line"><span style="color: #DCDCAA">mkdir</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">elm</span></span>
<span class="line"><span style="color: #DCDCAA">cd</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">elm</span></span>
<span class="line"><span style="color: #DCDCAA">elm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">init</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># fire up an editor</span></span>
<span class="line"><span style="color: #DCDCAA">gedit</span><span style="color: #D4D4D4"> &amp;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># open up an elm console</span></span>
<span class="line"><span style="color: #DCDCAA">elm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">repl</span></span></code></pre></div>



<p class="wp-block-paragraph">Add the &#8220;.&#8221; directory to elm.json. This will tell Elm to search for modules in there:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>    "source-directories": &#91;
        "src",
        "."
    &#93;,</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&quot;source-directories&quot;</span><span style="color: #D4D4D4">: &#91;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #CE9178">&quot;src&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #CE9178">&quot;.&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    &#93;,</span></span></code></pre></div>



<p class="wp-block-paragraph">Next up, make the file Sample.elm, and just keep it open in the editor:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>module Sample exposing (..)

add : Int -> Int -> Int
add a b = a + b

mul : Int -> Int -> Int
mul a b = a * b

sub : Int -> Int -> Int
sub a b = a - b</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">module</span><span style="color: #D4D4D4"> Sample </span><span style="color: #569CD6">exposing</span><span style="color: #D4D4D4"> (..)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #DCDCAA">add</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">:</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">Int</span><span style="color: #D4D4D4"> -&gt; </span><span style="color: #569CD6">Int</span><span style="color: #D4D4D4"> -&gt; </span><span style="color: #569CD6">Int</span></span>
<span class="line"><span style="color: #DCDCAA">add</span><span style="color: #D4D4D4"> a b </span><span style="color: #569CD6">=</span><span style="color: #D4D4D4"> a + b</span></span>
<span class="line"></span>
<span class="line"><span style="color: #DCDCAA">mul</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">:</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">Int</span><span style="color: #D4D4D4"> -&gt; </span><span style="color: #569CD6">Int</span><span style="color: #D4D4D4"> -&gt; </span><span style="color: #569CD6">Int</span></span>
<span class="line"><span style="color: #DCDCAA">mul</span><span style="color: #D4D4D4"> a b </span><span style="color: #569CD6">=</span><span style="color: #D4D4D4"> a * b</span></span>
<span class="line"></span>
<span class="line"><span style="color: #DCDCAA">sub</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">:</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">Int</span><span style="color: #D4D4D4"> -&gt; </span><span style="color: #569CD6">Int</span><span style="color: #D4D4D4"> -&gt; </span><span style="color: #569CD6">Int</span></span>
<span class="line"><span style="color: #DCDCAA">sub</span><span style="color: #D4D4D4"> a b </span><span style="color: #569CD6">=</span><span style="color: #D4D4D4"> a - b</span></span></code></pre></div>



<p class="wp-block-paragraph">That&#8217;s a bunch of <a href="https://sporto.gitbooks.io/elm-tutorial/content/en/01-foundations/02-functions.html">function definitions</a>.</p>



<p class="wp-block-paragraph">Jump back to the Elm REPL in the terminal:</p>



<pre class="wp-block-preformatted has-base-color has-contrast-background-color has-text-color has-background has-link-color wp-elements-4">&gt; import Sample exposing (..)<br>&gt; mul 2 3<br>6<br>&gt; sub 1 2<br>-1</pre>



<p class="wp-block-paragraph">You can type in more function definitions, and they&#8217;ll be available when you type them into the REPL.</p>



<p class="wp-block-paragraph">So, we&#8217;ve created functions so we can type out a language that looks like LISP:</p>


<div class="wp-block-html alignfull">
<pre>&gt; (add 1 2)
<font color="#FF55FF">3</font><font color="#555555"> : Int</font>
&gt; (add (mul 2 2) (mul 5 2) )
<font color="#FF55FF">14</font><font color="#555555"> : Int</font>
&gt; mul (add 2 3) (mul 2 2)
<font color="#FF55FF">20</font><font color="#555555"> : Int</font>
&gt; add (mul (mul 2 3) 5)
<font color="#00AAAA">&lt;function&gt;</font><font color="#555555"> : Int -&gt; Int</font>
&gt; add (mul (mul 2 3) 5) 100
<font color="#FF55FF">130</font><font color="#555555"> : Int</font>
</pre>
</div>


<p class="wp-block-paragraph">That second to last call to add returned a function. The function takes one argument. Putting a 100 after it added 30 to the 100.</p>



<p class="wp-block-paragraph">(add 1) returns a function that takes one argument, and returns a value that&#8217;s one added to the argument.</p>



<p class="wp-block-paragraph">(add 9) returns a function that takes one argument, and returns a value that&#8217;s 9 added to the argument.</p>



<p class="wp-block-paragraph">Elm has some syntax that messes with the ordering, called a pipe. Here&#8217;s the pipe in action:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>records
    |> map getCost
    |> filter (isOver 100)
    |> sum</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">records</span></span>
<span class="line"><span style="color: #D4D4D4">    |&gt; map getCost</span></span>
<span class="line"><span style="color: #D4D4D4">    |&gt; filter (isOver </span><span style="color: #B5CEA8">100</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    |&gt; sum</span></span></code></pre></div>



<p class="wp-block-paragraph">So, that makes sense. It&#8217;s like Unix pipes. Records piped into map getCost, piped into filter (isOver 100), piped into sum.</p>



<p class="wp-block-paragraph">In English: all the costs from records, filtered to be over 100, and summed.</p>



<p class="wp-block-paragraph">The pipe, |&gt;, rearranges the way functions work. These two function calls are the same:</p>



<pre class="wp-block-preformatted has-base-color has-contrast-background-color has-text-color has-background has-link-color wp-elements-5">&gt; add 1 2<br>3 : Int<br>&gt; 2 |&gt; add 1<br>3 : Int</pre>



<p class="wp-block-paragraph">What&#8217;s going on?</p>



<p class="wp-block-paragraph">&#8220;2 |&gt; add 1&#8221; means 2 passed to add 1.  What is &#8220;add 1&#8221;? </p>



<p class="wp-block-paragraph">(add 1) returns a function that takes a single argument, and adds 1 to it.</p>



<p class="wp-block-paragraph">The following are all the same ((2 + 3) * (2 * 2)):</p>



<pre class="wp-block-preformatted">&gt; mul (add 2 3) (mul 2 2)<br>20 : Int<br>&gt; (mul 2 2) |&gt; mul (add 2 3)<br>20 : Int<br>&gt; (2 |&gt; mul 2) |&gt; mul (3 |&gt; add 2)<br>20 : Int<br>&gt; 2 |&gt; mul 2 |&gt; mul (3 |&gt; add 2)<br>20 : Int</pre>



<p class="wp-block-paragraph">You can reformat the last one in the indented pipes layout:</p>



<pre class="wp-block-preformatted">2<br>    |&gt; mul 2<br>    |&gt; mul (3 |&gt; add 2)</pre>



<p class="wp-block-paragraph">Yeah, it doesn&#8217;t make anything clearer, but you can try to work out how Elm evaluates the final value, and it will help clarify the pipe |&gt;.</p>



<p class="wp-block-paragraph">To show what I mean, I&#8217;ll highlight (in red) functions that can resolve to a function:</p>



<pre class="wp-block-preformatted">2<br>    |&gt; <strong><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-windpress-red-600-color">mul 2</mark></strong><br>    |&gt; mul (3 |&gt; <strong><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-windpress-red-600-color">add 2</mark></strong>)</pre>



<p class="wp-block-paragraph">Next, we pass values (on the left of the |&gt;) into these functions, and they evaluate to values (in green).</p>



<pre class="wp-block-preformatted"><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-windpress-emerald-600-color"><strong>4</strong></mark><br>    |&gt; mul <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-windpress-emerald-600-color"><strong>5</strong></mark></pre>



<p class="wp-block-paragraph">That mul 5 will return a function:</p>



<pre class="wp-block-preformatted"><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-windpress-emerald-600-color"><strong>4</strong></mark><br>    |&gt; <strong><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-windpress-red-600-color">mul 5</mark></strong></pre>



<p class="wp-block-paragraph">Then, we pass 4 into the function returned by (mul 5) and evaluate.</p>



<pre class="wp-block-preformatted"><strong><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-windpress-teal-700-color">20</mark></strong></pre>



<p class="wp-block-paragraph">Obviously, there are more appropriate places to use pipe notation, and this isn&#8217;t one of them.</p>



<p class="wp-block-paragraph">This example below, however, is a good use of pipes.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>records
    |> map getCost
    |> filter (isOver 100)
    |> sum</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">records</span></span>
<span class="line"><span style="color: #D4D4D4">    |&gt; map getCost</span></span>
<span class="line"><span style="color: #D4D4D4">    |&gt; filter (isOver </span><span style="color: #B5CEA8">100</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    |&gt; sum</span></span></code></pre></div>



<p class="wp-block-paragraph">That is the same as:</p>



<pre class="wp-block-preformatted has-windpress-yellow-300-color has-secondary-background-color has-text-color has-background has-link-color wp-elements-6">(sum (filter (isOver 100) (map getCost records)))</pre>



<p class="wp-block-paragraph"></p><p>The post <a href="https://riceball.com/2026/09/03/learning-elm-pipe-tricks/">Learning Elm: pipe tricks</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/09/03/learning-elm-pipe-tricks/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Learning Elm</title>
		<link>https://riceball.com/2026/08/29/learning-elm/</link>
					<comments>https://riceball.com/2026/08/29/learning-elm/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sun, 30 Aug 2026 01:46:45 +0000</pubDate>
				<category><![CDATA[Human Learning]]></category>
		<category><![CDATA[Elm]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=30380</guid>

					<description><![CDATA[<p>I was having a hard time with the main tutorial, so I&#8217;m winding a different path through the language. 8/29: After doing the basics, I started hitting walls, and found the tutorial going all over the place, so I decided to dig through the Elm core libraries, and just try running commands: https://package.elm-lang.org/packages/elm/core/latest/ Typing things [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/08/29/learning-elm/">Learning Elm</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">I was having a hard time with the <a href="https://guide.elm-lang.org/">main tutorial</a>, so I&#8217;m winding a different path through the language.</p>



<div class="wp-block-group has-windpress-slate-200-background-color has-background has-global-padding is-layout-constrained wp-container-core-group-is-layout-9bf84538 wp-block-group-is-layout-constrained" style="padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--30)">
<p class="wp-block-paragraph">8/29: After doing the basics, I started hitting walls, and found the tutorial going all over the place, so I decided to dig through the Elm core libraries, and just try running commands: <a href="https://package.elm-lang.org/packages/elm/core/latest/">https://package.elm-lang.org/packages/elm/core/latest/</a></p>



<p class="wp-block-paragraph">Typing things out helps me to understand the syntax and also the notation in the docs.</p>
</div>



<p class="wp-block-paragraph">To get started, you need to <a href="https://guide.elm-lang.org/install/elm.html">install Elm</a>. Then, you&#8217;ll get the <code>elm</code> command, which is like <code>npm</code> or <code>composer</code>.  <code>elm</code> is a package manager and a build tool. Here&#8217;s part of the help when you type &#8220;elm&#8221;:</p>



<pre class="wp-block-preformatted">elm repl --help<br>elm init --help<br>elm reactor --help<br>elm make --help<br>elm install --help<br>elm bump --help<br>elm diff --help<br>elm publish --help</pre>



<p class="wp-block-paragraph">The main tools to use as a beginner are <code>elm reactor</code>, the web browser dev tool, and <code>elm repl</code>, the &#8220;console&#8221; where you can type Elm code and try it out.</p>



<p class="wp-block-paragraph">I started with <a href="https://package.elm-lang.org/packages/elm/core/latest/Array">Array</a>, <a href="https://package.elm-lang.org/packages/elm/core/latest/List">List</a>, and <a href="https://package.elm-lang.org/packages/elm/core/latest/Maybe">Maybe</a>. Also see the <a href="https://elm-lang.org/docs/syntax">syntax reference card</a> and the <a href="https://guide.elm-lang.org/core_language">core language reference</a>.</p>



<p class="wp-block-paragraph">It was a good way to get familiar with the notation:</p>


<pre class="wp-block-code"><span><code class="hljs language-php">fromList : <span class="hljs-keyword">List</span> a -&gt; <span class="hljs-keyword">Array</span> a</code></span></pre>


<p class="wp-block-paragraph">The Array.fromList function takes a list as an argument, and returns an array.</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">push : a -&gt; <span class="hljs-built_in">Array</span> a -&gt; <span class="hljs-built_in">Array</span> a</code></span></pre>


<p class="wp-block-paragraph">The push function takes a value, and an array as arguments, and returns an array with the value appended to the end.</p>



<p class="wp-block-paragraph">Arrays and Lists made sense, but Maybe was different. Type these lines into the REPL.</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-keyword">import</span> <span class="hljs-built_in">Array</span> exposing (..)

x = fromList &#91;<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]
<span class="hljs-keyword">get</span> 1 x

-- returns Just 2 : Maybe number
</code></span></pre>


<p class="wp-block-paragraph">The return value, Just 2, is not 2. You expect 2, but get Just 2. What is up with that?</p>



<p class="wp-block-paragraph">Just 2 is of type Maybe. Maybe values can be &#8220;Just number&#8221; or &#8220;Nothing&#8221;. From the docs:</p>



<pre class="wp-block-preformatted">type Maybe a<br>    = Just a<br>    | Nothing</pre>



<p class="wp-block-paragraph">&#8220;Represent values that may or may not exist. It can be useful if you have a record field that is only filled in sometimes. Or if a function takes a value sometimes, but does not absolutely need it.&#8221;</p>



<p class="wp-block-paragraph">So, this looked weird to me, but here&#8217;s a quick way to convert it to a normal value:</p>


<pre class="wp-block-code"><span><code class="hljs">-- here's the function
withDefault : a -&gt; Maybe a -&gt; a

-- usage
withDefault 0 (Just 2)
-- returns the value 2 : number</code></span></pre>


<p class="wp-block-paragraph">OK, that is still weird. (Most languages have type coercion or functions to convert values.)</p>



<p class="wp-block-paragraph">Here&#8217;s an example from the <a href="https://elm-lang.org/docs/syntax">syntax guide</a>:</p>


<pre class="wp-block-code"><span><code class="hljs language-xml"><span class="hljs-tag">&lt;<span class="hljs-name">code</span>&gt;</span>case maybeList of
    Just xs -&gt; xs
    Nothing -&gt; &#91;]<span class="hljs-tag">&lt;/<span class="hljs-name">code</span>&gt;</span></code></span></pre>


<p class="wp-block-paragraph">This is a different way to coerce values. It switches based on the <strong>type variant</strong> of maybeList.</p>



<p class="wp-block-paragraph">So <strong>Maybe</strong> is a <strong>type</strong>, with two <strong>variants</strong> &#8220;<strong>Just</strong> xs&#8221; and &#8220;<strong>Nothing</strong>&#8220;.</p>



<p class="wp-block-paragraph">The case switching isn&#8217;t based on the value of the variable, but on the variant.</p>



<p class="wp-block-paragraph">(This might look like a variant is, itself, a type. This isn&#8217;t the case, because maybeList must be a Maybe. The case switch will match only variants of Maybe. This is more restrictive than the case switch statements you see in OOP languages with a typeof() operator.)</p>



<p class="has-tertiary-background-color has-background wp-block-paragraph">I&#8217;ll stop at this point, because types are important to Elm. I have to spend more time studying it. It&#8217;s reminding me of types in Haskell: and that means it&#8217;s part of how the program executes.</p>



<p class="wp-block-paragraph"><a href="https://dev.to/jigargosar/elm-vs-the-feature-addiction-epidemic-in-programming-ach">https://dev.to/jigargosar/elm-vs-the-feature-addiction-epidemic-in-programming-ach</a></p>



<p class="wp-block-paragraph"><a href="https://riptutorial.com/elm">https://riptutorial.com/elm</a></p>



<p class="wp-block-paragraph"><a href="https://guide.elm-lang.org/types">https://guide.elm-lang.org/types</a></p>



<p class="wp-block-paragraph"><a href="https://learnyouanelm.github.io/pages/03-types.html">https://learnyouanelm.github.io/pages/03-types.html</a></p>



<p class="wp-block-paragraph"><a href="https://www.elmcraft.org/">https://www.elmcraft.org/</a> </p>



<p class="wp-block-paragraph"><a href="https://elmprogramming.com/">https://elmprogramming.com/</a></p>



<p class="wp-block-paragraph"><a href="https://lamdera.com">https://lamdera.com</a></p>



<p class="wp-block-paragraph"><a href="https://github.com/sporto/awesome-elm">https://github.com/sporto/awesome-elm</a></p>



<p class="wp-block-paragraph"><a href="https://pragmaticstudio.com/tutorials/what-is-elm">https://pragmaticstudio.com/tutorials/what-is-elm</a></p>



<p class="wp-block-paragraph"><a href="https://www.sitepoint.com/functional-reactive-programming-elm-introduction/#google_vignette">https://www.sitepoint.com/functional-reactive-programming-elm-introduction/#google_vignette</a></p>



<p class="wp-block-paragraph"><a href="https://en.wikibooks.org/wiki/Elm_programming_language">https://en.wikibooks.org/wiki/Elm_programming_language</a></p>



<p class="wp-block-paragraph"><a href="https://www.toptal.com/developers/front-end/getting-started-elm-language">https://www.toptal.com/developers/front-end/getting-started-elm-language</a></p>



<p class="wp-block-paragraph"><a href="https://dev.to/marciofrayze/why-is-elm-such-a-delightful-programming-language-2em8">https://dev.to/marciofrayze/why-is-elm-such-a-delightful-programming-language-2em8</a></p>



<p class="wp-block-paragraph"><a href="https://github.com/elm">https://github.com/elm</a></p>



<p class="wp-block-paragraph"></p><p>The post <a href="https://riceball.com/2026/08/29/learning-elm/">Learning Elm</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/08/29/learning-elm/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
