<rss version="2.0">
  <channel>
    <title>UCL on Leon Mika</title>
    <link>https://lmika.org/categories/ucl/</link>
    <description></description>
    
    <language>en</language>
    
    <lastBuildDate>Wed, 04 Feb 2026 07:51:56 +1100</lastBuildDate>
    
    <item>
      <title></title>
      <link>https://lmika.org/2026/02/04/over-the-weekend-curious-to.html</link>
      <pubDate>Wed, 04 Feb 2026 07:51:56 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2026/02/04/over-the-weekend-curious-to.html</guid>
      <description>&lt;p&gt;Over the weekend, curious to know how well it&amp;rsquo;ll do, I asked ChatGPT to generate some code in &lt;a href=&#34;https://lmika.org/categories/ucl/&#34;&gt;UCL&lt;/a&gt;, the toy language I sometimes write about here. I asked it to product a script that would print out the Fibonacci sequence up to a given value. It didn&amp;rsquo;t do too well, producing a script which looked like a strange hybrid between TCL and shell.&lt;/p&gt;
&lt;p&gt;This was somewhat expected. What wasn&amp;rsquo;t expected was to see UCL pop up as a topic within Pulse the next day:&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2026/out-20260204-074118.png&#34; width=&#34;600&#34; height=&#34;1303&#34; alt=&#34;Auto-generated description: A digital interface displays two sections: one describing a Fibonacci demo project and another about assembling a UCL example suite, both accompanied by illustrative images.&#34;&gt;
&lt;p&gt;Very amusing.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2026/01/26/was-not-expecting-to-spend.html</link>
      <pubDate>Mon, 26 Jan 2026 09:36:01 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2026/01/26/was-not-expecting-to-spend.html</guid>
      <description>&lt;p&gt;Was not expecting to spend yesterday morning working on Dequoter, my Boop clone. Opened it up to do some light work and when I looked up, a couple of hours have passed. Added a few more processors to deal with lines, such as splitting and joining on commas. Added a status bar for processes that return information rather than filter text, such as returning a line count.&lt;/p&gt;
&lt;p&gt;Also integrated UCL, because of course I did. Added two commands: a &lt;code&gt;UCL: Evaluate&lt;/code&gt; which executes the input as a UCL script and displays the response in the status bar, and a &lt;code&gt;UCL: Replace&lt;/code&gt; which replaces the UCL script with it&amp;rsquo;s output. This makes it possible to generate text from scripts, like a bunch of lines to test out the line count processor:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;map (seq 20) { |n| &amp;#34;Line $n&amp;#34; } | strs:join &amp;#34;\n&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2026/out-20260126-093456.png&#34; width=&#34;600&#34; height=&#34;478&#34; alt=&#34;Auto-generated description: A computer window titled Dequoter displays a list numbered from 0 to 19.&#34;&gt;
&lt;p&gt;It&amp;rsquo;ll also make for a useful scratchpad for testing out some UCL commands.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Devlog: Dynamo Browse - Item View Annotations and Asynchronous Tasks</title>
      <link>https://lmika.org/2025/11/04/devlog-dynamo-browse-item-view.html</link>
      <pubDate>Tue, 04 Nov 2025 21:42:40 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2025/11/04/devlog-dynamo-browse-item-view.html</guid>
      <description>&lt;p&gt;The laundry list of things to do in Dynamo Browse has grown over the last week, as I find myself wanting using it and wanting more from it. I&amp;rsquo;ve knocked off many of the small ones: fixing bugs, making it easier to get the first item from a result set. The time has come to tackle some of the larger ones.&lt;/p&gt;
&lt;p&gt;The first is the ability to annotate fields in the item view, as in add additional information to the right of the value. I would personally find that useful for describing the value of an other table using it&amp;rsquo;s ID. But the point is that it can be anything. I&amp;rsquo;d like users to add these annotations via extensions, using UCL. The way I&amp;rsquo;m thinking of doing this is by &amp;ldquo;installing&amp;rdquo; a field annotator, something along the lines as follows:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;ui:add-item-annotator { |rs attr_path| 
    return &amp;#34;&amp;#34;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will add an annotator which will take a result set, and a path to an attribute. It will return the annotated value. We&amp;rsquo;ll see how well this will work, but first I&amp;rsquo;ll need to build the Go types. Rendering the item view is done using an &lt;code&gt;ItemRenderer&lt;/code&gt; which basically walks through the attributes of an item and renders it as a table. I think I&amp;rsquo;ll change this to take an item annotation. I also realised I need a type to represent the attribute path. I think a simple linked list would work here. Here&amp;rsquo;s what I got:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;AttrPathNode&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Index&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;IsIndex&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Parent&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;AttrPathNode&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The trouble is representing both string attribute names and numerical indicies in the same type. Go doesn&amp;rsquo;t have a great way of doing this, so I&amp;rsquo;ve gone with something simple and added boolean which would be true if the node is actually an integer index to a list or set.&lt;/p&gt;
&lt;p&gt;Actually, that may not be necessary. Poking around the renderer code, I found this type used to represent the sub items of an item:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SubItem&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Key&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Renderer&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So I can simply use strings for the key. Good to know. Okay, added a test annotator and gave it a quick test:
&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-03-at-20.37.46.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;8765091e77c1a5bd3340e2f3fa6a373e&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-03-at-20.37.46.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-11-03 at 20.37.46.png&#34; 
        
  /&gt;
&lt;/a&gt;


Not bad, although found some glaring issues. It would be nice if the annotation was closer to the value. And laying out the annotations in a dedicated column will cause the entire column to shift as I move through the items. So instead of making it a separate column, I&amp;rsquo;ll try simply concatenating it to the end of the value. I&amp;rsquo;ll also apply the meta-info styling to dim the text a little:
&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-03-at-20.39.24.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;8765091e77c1a5bd3340e2f3fa6a373e&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-03-at-20.39.24.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-11-03 at 20.39.24.png&#34; 
        
  /&gt;
&lt;/a&gt;


That&amp;rsquo;s much better. I&amp;rsquo;m banking on only a few attributes having annotations, so I&amp;rsquo;m hoping it won&amp;rsquo;t be as busy as it looks here.&lt;/p&gt;
&lt;p&gt;Now to consider the UCL integration. Hmm, how am I going to connect the two? As expected, injecting the annotation directly into &lt;code&gt;ItemRenderer&lt;/code&gt; would introduce a dependency loop. What I could do instead is add a setter allowing the caller of the &lt;code&gt;ItemRenderer&lt;/code&gt; to change the annotation on the fly, and inject the &lt;code&gt;ItemRenderer&lt;/code&gt; as a dependency of the command controller.&lt;/p&gt;
&lt;p&gt;Implemented this, and it was actually easier than I thought.  Now to test this. I settled on the following UCL command:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;ui:set-item-annotator { |rs item path| 
    &amp;#34;annotation&amp;#34;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rs&lt;/code&gt; is the result set&lt;/li&gt;
&lt;li&gt;&lt;code&gt;item&lt;/code&gt; is the item being rendered in the view&lt;/li&gt;
&lt;li&gt;&lt;code&gt;path&lt;/code&gt; is the attribute path, represented as a list.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The attribute path is a new proxy, just to reduce the amount of memory copying between Go and UCL. I kept the same list index semantics, where &amp;gt; 0 starts from the left, and &amp;lt; 0 starts from the right, but it was a little mind bending to reverse this for a linked list.&lt;/p&gt;
&lt;p&gt;A simple annotator which returns the currently displayed item value as an annotation can be implemented as follows:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;ui:set-item-annotator { |rs item path|
    $item.($path.(-1))
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here it is in action:
&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-03-at-20.41.25.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;8765091e77c1a5bd3340e2f3fa6a373e&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-03-at-20.41.25.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-11-03 at 20.41.25.png&#34; 
        
  /&gt;
&lt;/a&gt;


Brilliant, it&amp;rsquo;s working! Naturally as commands are simple UCL statements, this could be entered on the command line.&lt;/p&gt;
&lt;p&gt;One thing to consider is that unlike normal commands, the UCL block rendering the annotation is running on the UI thread. Not sure I like this, but the amount of effort required to change this would be significant. I guess I&amp;rsquo;ll just tell everyone to keep annotation rendering fast. And as it&amp;rsquo;s currently implement, it is reasonably fast. Or more accurately, it&amp;rsquo;s not noticeably slow, which is good enough.&lt;/p&gt;
&lt;p&gt;The next feature to add to Dynamo Browse is a way to asynchronously schedule blocks. I think it may be worth tapping into the existing command looper in some way.&lt;/p&gt;
&lt;p&gt;Commands in Dynamo Browse are invoked on a dedicated goroutine. Calling &lt;code&gt;execute()&lt;/code&gt; will attempt to send a command via a channel. If that fails, &lt;code&gt;execute()&lt;/code&gt; will return an error indicating that a command is currently running. This keeps running UCL code off the UI thread, and it also makes it possible to implement commands like &lt;code&gt;ui:prompt&lt;/code&gt; synchronously from the UCL code&amp;rsquo;s perspective, when in reality it pauses this goroutine and sends a message to the UI with a callback to resume the thread:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;uiModule&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;uiPrompt&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;args&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ucl&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;CallArgs&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;) (&lt;span style=&#34;color:#a6e22e&#34;&gt;any&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;prompt&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;args&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Bind&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;prompt&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;resChan&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;cancelChan&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt;{})  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;commandctrl&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PostMsg&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;events&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PromptForInputMsg&lt;/span&gt;{  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;Prompt&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;prompt&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;OnDone&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;tea&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Msg&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;resChan&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            },  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;OnCancel&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() &lt;span style=&#34;color:#a6e22e&#34;&gt;tea&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Msg&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;cancelChan&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt;{}{}  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        })  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }()  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;select&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;resChan&lt;/span&gt;:  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;cancelChan&lt;/span&gt;:  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Done&lt;/span&gt;():  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Err&lt;/span&gt;()  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So tapping into this event loop would be nice. But how does one do so?&lt;/p&gt;
&lt;p&gt;I think, probably the simplest way to do so is with buffered channels. These are bounded, meaning that there will be an upper limit to the number of pending tasks, but maybe that&amp;rsquo;s not a bad thing. Having too many pending tasks crowding out the user&amp;rsquo;s ability to run commands will probably make for a poor user experience. So let&amp;rsquo;s set the limit to something quite generous, say 50, and integrate it into the event loop:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;select&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;cmdChan&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;cmdChan&lt;/span&gt;:  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ExecuteAndWait&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;cmdChan&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;cmd&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;postMessage&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;events&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Error&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;))  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;postMessage&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;events&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusMsg&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sprint&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt;)))  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;execCtx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;requestRefresh&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;postMessage&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;events&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResultSetUpdated&lt;/span&gt;{})  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// New code here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;task&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;pendingTaskChan&lt;/span&gt;:  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;task&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;task&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;postMessage&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;events&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Error&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;))  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now for the UCL API. I have an idea of adding a new &lt;code&gt;async&lt;/code&gt; package for this, which will provide commands for running things asynchronously. It&amp;rsquo;s simplest command would be &lt;code&gt;async:do&lt;/code&gt;, which will schedule a block when the command loop is free. So invoking the following:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;ui:command testasync {  
    echo &amp;#34;This&amp;#34;
    async:do {
        echo &amp;#34;Other&amp;#34;
        async:do { echo &amp;#34;Sierra&amp;#34; }
    }
    async:do {
        echo &amp;#34;Romeo&amp;#34;
    }
    echo &amp;#34;That&amp;#34;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Should display:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;This
That
Other
Romeo
Sierra
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the logs. Trying it out and here&amp;rsquo;s how it looks:
&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-03-at-21.31.42.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;8765091e77c1a5bd3340e2f3fa6a373e&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-03-at-21.31.42.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-11-03 at 21.31.42.png&#34; 
        
  /&gt;
&lt;/a&gt;


Okay, that&amp;rsquo;s pretty good. Now to build on this. The next thing to add is a command that will schedule tasks in the future, similar to &lt;code&gt;window.setTimeout()&lt;/code&gt;. For this, I plan to use the &lt;a href=&#34;https://github.com/go-co-op/gocron&#34;&gt;gocron&lt;/a&gt; package. Lots there, but for my purpose, I plan to use the &lt;a href=&#34;https://pkg.go.dev/github.com/go-co-op/gocron/v2@v2.17.0#OneTimeJob&#34;&gt;OneTimeJob&lt;/a&gt; type. It does feel like bringing in a crane to lift an empty wood pallet, but the alternative is building my own scheduler (or getting AI to vibe-code one) using a heap. Maybe something for later, but I think this is fine for now.&lt;/p&gt;
&lt;p&gt;To make use of this, I&amp;rsquo;ll add &lt;code&gt;async:in&lt;/code&gt;, which takes a timeout in seconds, and a block to run. To test this, I&amp;rsquo;ll do the classic &amp;ldquo;count down&amp;rdquo; tests:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;proc countdown { |from|
    if (le $from 0) {
        echo &amp;#34;Blast off!!&amp;#34;
        return
    }
    echo &amp;#34;$from&amp;#34;
    async:in 1 { countdown (sub $from 1) }
}

ui:testasync {
    countdown 10
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here it is in action:&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-03-at-22.12.51.mp4&#34; poster=&#34;https://lmika.org/uploads/2025/72bad33388.png&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;One last thing to add to async, the ability to run a query in the background and execute a block once the results are available, keeping long running queries off the UCL goroutine. I think for this I will add another thread-pool which will execute up to two queries in the background, then schedule a task to run once the results are ready.&lt;/p&gt;
&lt;p&gt;The API for running queries is pretty well established, to the point that I&amp;rsquo;ve actually got a helper functions which deal with the UCL side of things, so it&amp;rsquo;s just a matter of implementing an asynchronous version of this. I&amp;rsquo;m thinking of an interface along the following lines:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;async:query &amp;lt;query&amp;gt; { |rs|
    # do something with the result-set $rs
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It should also support keyword arguments too. Unfortunately, UCL requires keyword arguments to be placed after the positional arguments, so they would need to be placed after the block, which is a little yucky.&lt;/p&gt;
&lt;p&gt;Implemented the code, now for the test. This one&amp;rsquo;s a little contrived. What it does is asynchronously run a query on startup, counting the number of opened and closed offices in the &lt;code&gt;business-addresses&lt;/code&gt; table. Once those results are available, it will install a new column annotation, which will display the count to the right of the &lt;code&gt;officeOpened&lt;/code&gt; fields.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;proc _prep_officeCount {
    openedOffices = 0
    closedOffices = 0

    async:query &amp;#39;officeOpened=true&amp;#39; { |rs|
        openedOffices = len $rs
        async:query &amp;#39;officeOpened=false&amp;#39; { |rs|
            closedOffices = len $rs

            ui:set-item-annotator { |rs item path|
                if (eq $path.(-1) &amp;#34;officeOpened&amp;#34;) {
                    if $item.officeOpened {
                        &amp;#34;Count = ${openedOffices}&amp;#34;
                    } else {
                        &amp;#34;Count = ${closedOffices}&amp;#34;
                    }
                } else {
                    &amp;#34;&amp;#34;
                }
            }
        } -table business-addresses
    } -table business-addresses
}

_prep_officeCount
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It is contrived, but I&amp;rsquo;m hoping to use this in a real setting where I annotate ID fields with a value I retrieve from another table, so a use case like this is pretty close to why I built this feature. Because the queries are running in the background, the goal is to avoid blocking the UI thread, but since this runs on startup before the user selects a table, the table needs to be specified as part of the call. I may have to have a think of how I am to fix that.&lt;/p&gt;
&lt;p&gt;But here it is working. Note the &lt;code&gt;Count = 244&lt;/code&gt; next to the &lt;code&gt;officeOpened&lt;/code&gt; field:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-04-at-13.49.19.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;8765091e77c1a5bd3340e2f3fa6a373e&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-04-at-13.49.19.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-11-04 at 13.49.19.png&#34; 
        
  /&gt;
&lt;/a&gt;


Excellent. The next thing to do is try this out in a real setting. I finished off making a proper goroutine pool for the task that actually runs the query — which I&amp;rsquo;m calling the &amp;ldquo;aux task pool&amp;rdquo; — and a few other changes, like making the meta information a little easier to see.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Devlog: UCL - Adding Some Missing Library Functions</title>
      <link>https://lmika.org/2025/10/27/devlog-ucl-adding-some-missing.html</link>
      <pubDate>Mon, 27 Oct 2025 22:26:14 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2025/10/27/devlog-ucl-adding-some-missing.html</guid>
      <description>&lt;p&gt;Working on UCL, adding some missing builtins I&amp;rsquo;ve been finding myself wanting. Nothing too interesting. Just functions like &lt;code&gt;strs:has-prefix&lt;/code&gt;, &lt;code&gt;strs:trim-suffix&lt;/code&gt;, and other functions involving strings and lists that are missing. That sort of thing.&lt;/p&gt;
&lt;p&gt;I am facing some decisions around &lt;code&gt;strs:substr&lt;/code&gt;. See, the usual way these builtins are validating arguments is that if there are more arguments than are necessary, they are generally just ignored. One could describe this as the &amp;ldquo;JavaScript&amp;rdquo; approach to argument validation: open Node and evaluate &lt;code&gt;&amp;quot;hello&amp;quot;.substr(1,2,3,4,5,6,7,8,9)&lt;/code&gt; and one will get the same result as if they simply typed in &lt;code&gt;&amp;quot;hello&amp;quot;.substr(1,2)&lt;/code&gt;. But now I&amp;rsquo;m wondering if it&amp;rsquo;s better to assert that the arguments are either one or two positions, along with the string. What if I wanted to add more positional arguments in the future?&lt;/p&gt;
&lt;p&gt;Although in practice, why would I want to do that? Well, okay, I do have an idea of for taking multiple substrings in a single call. So could be useful? Ah, probably doesn&amp;rsquo;t matter: it&amp;rsquo;ll just be me using this for now.&lt;/p&gt;
&lt;p&gt;Anyway, &lt;code&gt;strs:substr&lt;/code&gt;. One deviation from JavaScript I think I would like to do is that if a single number is used, that would be treated as the end position of the substring; as oppose to JavaScript which treats it as the start position. So running &lt;code&gt;strings:sub &amp;quot;hello, world&amp;quot; 5&lt;/code&gt; will return &lt;code&gt;&amp;quot;hello&amp;quot;&lt;/code&gt;, rather than &lt;code&gt;&amp;quot;, world&amp;quot;&lt;/code&gt;. To start from the right, a negative position can be used: &lt;code&gt;strings:sub &amp;quot;hello, world&amp;quot; -5&lt;/code&gt; will return &lt;code&gt;&amp;quot;world&amp;quot;&lt;/code&gt;. Two numbers will be treated as a start (inclusive) and end (exclusive) positions, like most other languages; although both can be negative which will set the position from the right side.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;strs:substr &amp;#34;hello, world&amp;#34; 5   
--&amp;gt; &amp;#34;hello&amp;#34;

strs:substr &amp;#34;hello, world&amp;#34; -5  
--&amp;gt; &amp;#34;world&amp;#34;

strs:substr &amp;#34;hello, world&amp;#34; 3 10
--&amp;gt; &amp;#34;lo, wor&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Okay, that&amp;rsquo;s working for strings. Need to do the same thing for lists. I could almost use the same function.&lt;/p&gt;
&lt;p&gt;Oh, I keep forgetting that I need to worry about nils. How should &lt;code&gt;sublists&lt;/code&gt; work if the passed in list is nil? Maybe it&amp;rsquo;s better to just return a nil. Less hassle than requiring the user to deal with nil values. I&amp;rsquo;ll start with that approach, but I may change that the future.  Should I do the same for &lt;code&gt;strs:substr&lt;/code&gt;? Hmm, no. I think I&amp;rsquo;ll keep the default binding rules for nil to strings, which is basically convert it into an empty string. That saves me from changing the binding logic. Maybe I should lock that decision in with a test.&lt;/p&gt;
&lt;p&gt;Hmm, also, many of the other list builtins support iterators. If I were going to add iterator support to &lt;code&gt;sublist&lt;/code&gt; , then how would I handle the negative numbers? Iterators, by definition, can be boundless. Maybe leave iterator support out for now.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;lists:sublist [a b c] 1
--&amp;gt; [a]

lists:sublist [a b c] -1
--&amp;gt; [c]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It also looks like the argument binder has made my mind up about nils for me. I added the test which testing for nils, and I got an &lt;code&gt;expected listable&lt;/code&gt; error.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;lists:sublist () 1
--&amp;gt; error: expected listable
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I think that&amp;rsquo;s fine. Might be better to fail on nils actually.&lt;/p&gt;
&lt;p&gt;Getting back to the argument question raised earlier, I did run into an issue where I was using &lt;code&gt;strs:split&lt;/code&gt; without a second argument. When one does that, UCL will do something similar to Go, and return a list of each individual rune. I think that&amp;rsquo;s a useful feature, but I think I&amp;rsquo;d prefer it if that option was explicit, and if a second argument were not set, raise an error.&lt;/p&gt;
&lt;p&gt;Okay, a few more items on my todo list. I need a string replace function. I generally prefer such a function to replace all the instances of a string, rather than just the first; but that might be pushing my preference a little too far. So I&amp;rsquo;ll settle with replacing the first instance of a substring and add an &lt;code&gt;-all&lt;/code&gt; flag to replace all instances.&lt;/p&gt;
&lt;p&gt;Actually, no. Go has support for specifying a count, so I&amp;rsquo;ll use that by adding an &lt;code&gt;-n COUNT&lt;/code&gt; option. If N is unset, then all the substrings are replaced.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;strs:replace &amp;#34;hello hello hello&amp;#34; &amp;#34;hello&amp;#34; &amp;#34;world&amp;#34;
--&amp;gt; world world world

strs:replace &amp;#34;hello hello hello&amp;#34; &amp;#34;hello&amp;#34; &amp;#34;world&amp;#34; -n 1
--&amp;gt; world hello hello
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Also, given that this is using Go&amp;rsquo;s builtin &lt;code&gt;strings.Replace&lt;/code&gt; function, setting &amp;ldquo;match&amp;rdquo; to the empty string will cause &lt;code&gt;replace&lt;/code&gt; to match between each rune, plus the start and end of the
string.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;strs:replace &amp;#34;each one&amp;#34; &amp;#34;&amp;#34; &amp;#34;|&amp;#34;
--&amp;gt; |e|a|c|h| |o|n|e|
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Could be useful, so I&amp;rsquo;ll keep this feature in.&lt;/p&gt;
&lt;p&gt;Nearing the end now: adding an &lt;code&gt;-in&lt;/code&gt; switch to &lt;code&gt;os:exec&lt;/code&gt; to set stdin for an command. The original idea was to name the switch &lt;code&gt;-stdin&lt;/code&gt;, and I also considered &lt;code&gt;-input&lt;/code&gt;. But when writing the tests, I naturally settled on &lt;code&gt;-in&lt;/code&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;os:exec tr &amp;#39;[a-z]&amp;#39; &amp;#39;[A-Z]&amp;#39; -in &amp;#34;hello&amp;#34;
--&amp;gt; HELLO
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It would&amp;rsquo;ve been nice to accept stdin from a pipe. Sadly, that&amp;rsquo;s not possible with how pipes actually work.&lt;/p&gt;
&lt;p&gt;And the last one: adding a &lt;code&gt;nil?&lt;/code&gt; builtin, which will return true if the given item is nil.  I guess in the grand scheme of things, it&amp;rsquo;s probably not strictly necessary, as anything that&amp;rsquo;s not zero, including nil, will be true. And one could always use &lt;code&gt;eq $thing ()&lt;/code&gt; to test if &lt;code&gt;$thing&lt;/code&gt; is nil. So I may leave this one on the backlog.&lt;/p&gt;
&lt;p&gt;Okay, finished. I wanted to add some stuff to Dynamo Browse, but I ran out of time. I will update the version of UCL used by Dynamo Browse, but all that other stuff will need to wait for tomorrow.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/10/24/its-funny-how-i-approach.html</link>
      <pubDate>Fri, 24 Oct 2025 11:19:41 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2025/10/24/its-funny-how-i-approach.html</guid>
      <description>&lt;p&gt;It&amp;rsquo;s funny how I approach certain features in the tools I make, such as adding UCL to Dynamo Browse. It&amp;rsquo;s been several months since I&amp;rsquo;ve done this, and I haven&amp;rsquo;t really used it for anything substantial until today. I guess because I get the sense that it&amp;rsquo;s half-finished (mainly due to the fact that it is half-finished) I tend to approach such features gingerly: in a careful way so as to avoid any problems. That&amp;rsquo;s probably not the best way to approach these features though. They need to be taken through the ringer, and just used, lest I never find their limitations or bugs that need to be fixed.&lt;/p&gt;
&lt;p&gt;Anyway, this is a long winded way of saying that I&amp;rsquo;m glad I actually replaced the old scripting engine in Dynamo Browse with UCL. It was added to be used, and it actually came in useful today.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Devlog: UCL — Comparing UCL To Some Early Ideas</title>
      <link>https://lmika.org/2025/08/22/devlog-ucl-comparing-it-to.html</link>
      <pubDate>Fri, 22 Aug 2025 12:14:02 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2025/08/22/devlog-ucl-comparing-it-to.html</guid>
      <description>&lt;p&gt;I was browsing through some very old notes I had when I came across one that contain an idea for a hypothetical shell-like command language, sort of what UCL was designed for. It was designed for a project called Nuget, which was a CLI torrent downloader (now defunct). Much like UCL, it was REPL based with a simple token-based command language, and I was thinking of ways to extend this to including scripting. Here&amp;rsquo;s the note in full:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The nuget command language will be something very similar to shell. It will be used to configure nuget (in an RC file), and configure extensions.&lt;/p&gt;
&lt;p&gt;Example - check that the VPN is running&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let piaCtlState = !piactl get connectionstate

if eval &#39;trim(${piaCtlState}) ne &amp;quot;Connected&amp;quot;&#39; {
    notice &amp;quot;Warn: VPN not connected.  Use &#39;piactl&#39; to connect&amp;quot;
}

on newjob {
    on done { echo &amp;quot;Job done: ${job}&amp;quot; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;I never implemented this language, opting to simply use TCL. But it&amp;rsquo;s interesting to see the desire of having an embeddable language for both REPLs and scripting alive and well back in February 2021 (the note&amp;rsquo;s datestamp).&lt;/p&gt;
&lt;p&gt;Assuming that UCL existed at the time, I image the script would&amp;rsquo;ve looked a little less TCL-ly and a little closer to how Go templates work. Maybe something likes the following, assuming that the built-ins were implemented:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;piaCtlState = os:shell &amp;#34;piactl get connectionstate&amp;#34;

if (ne (strs:trim $piaCtlState) &amp;#34;Connected&amp;#34;) {
    notice &amp;#34;Warn: VPN not connected.  Use &amp;#39;piactl&amp;#39; to connect&amp;#34;
}

# I&amp;#39;m guessing &amp;#39;on&amp;#39; in the original idea would have job as a global variable.
# UCL can simply pass it in as an argument.
on newjob { |job|
  on done { echo &amp;#34;Job done: $job&amp;#34; }
}
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    
    <item>
      <title>Devlog: UCL — More About The Set Operator</title>
      <link>https://lmika.org/2025/06/14/devlog-ucl-more-about-the.html</link>
      <pubDate>Sat, 14 Jun 2025 12:35:00 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2025/06/14/devlog-ucl-more-about-the.html</guid>
      <description>&lt;p&gt;I made a decision around the set operator in UCL this morning.&lt;/p&gt;
&lt;p&gt;When I added the set operator, I made it such that when setting variables, you had to include the leading dollar sign:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$a = 123
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The reason for this was that the set operator was also to be used for setting pseudo-variables, which had a different prefix character.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;@ans = &amp;#34;this&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I needed the user to include the &lt;code&gt;@&lt;/code&gt; prefix to distinguish the two, and since one variable type required a prefix, it made sense to require it for the other.&lt;/p&gt;
&lt;p&gt;I’ve been trying this for a while, and I’ve deceided I didn’t like it. It felt strange to me. It shouldn&amp;rsquo;t, really, as it&amp;rsquo;s similar to how variable assignments work in Go’s templating language, which I consider an inspiration for UCL. On the other hand, TCL and Bash scripts, which are also inspirations, require the variable name to be written without the leading dollar sign in assignments. Heck, UCL itself still had constructs where referencing a name for a variable is done so without a leading dollar sign, such as block inputs. And I had no interest in changing that:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;proc foo { |x|
    echo $x
}

for [1 2 3] { |v| foo $v }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So I made the decision to remove the need for the dollar sign prefix in the set operator. Now, when setting a variable, only the variable name can be used:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;msg = &amp;#34;Hello&amp;#34;
echo $msg
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In fact, if one were to use the leading dollar sign, the program will fail with an error.&lt;/p&gt;
&lt;p&gt;This does have some tradeoffs. The first is that I still need to use the &lt;code&gt;@&lt;/code&gt; prefix for setting pseudo variables, and this change will violate the likeness of how the two look in assignments:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;@ans = 123
bla = 234
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The second is that this breaks the likeness of how a sub-index looks  when reading it, verses how it looks when it&amp;rsquo;s being modified:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;a = [1 2 3]
a.(1) = 4
$a
--&amp;gt; [1 4 3]
$a.(1)
--&amp;gt; 4
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(One could argue that the dollar sign prefix makes sense here as the evaluator is dereferencing the list in order to modify the specific index. That&amp;rsquo;s a good argument, but it feels a little bit too esoteric to justify the confusion it would add).&lt;/p&gt;
&lt;p&gt;This sucks, but I think they&amp;rsquo;re tradeoffs worth making. UCL is more of a command language than a templating language, so when asked to imagine similar languages, I like to think one will respond with TCL or shell-scripts, rather than Go templates.&lt;/p&gt;
&lt;p&gt;And honestly, I think I just prefer it this way. I feel that I&amp;rsquo;m more likely to set regular variables rather than pseudo-variables and indicies. So why not go with the approach that seems nicer if you&amp;rsquo;re likely to encounter more often.&lt;/p&gt;
&lt;p&gt;Finally, I did try support both prefixed and non-prefixed variables in the set operator, but this just felt like I was shying away from making a decision. So it wasn&amp;rsquo;t long before I scrapped that.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Devlog: Dynamo-Browse Now Scanning For UCL Extensions</title>
      <link>https://lmika.org/2025/05/25/devlog-dynamobrowse-now-scanning-for.html</link>
      <pubDate>Sun, 25 May 2025 14:55:49 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2025/05/25/devlog-dynamobrowse-now-scanning-for.html</guid>
      <description>&lt;p&gt;Almost finished integrating UCL with Dynamo-Browse. As stated earlier, the goal is to use UCL for both the command and scripting language. Today, the goal was closer, with a development version of Dynamo-Browse no longer using old extension scripting language, and now scanning and evaluating UCL-based extensions on launch time.&lt;/p&gt;
&lt;p&gt;This required some changes in how UCL evaluated script files. There&amp;rsquo;s a new &lt;code&gt;ucl.WithSubEnv()&lt;/code&gt; option that can be passed into  &lt;code&gt;inst.Eval()&lt;/code&gt; to instruct the evaluator to fork the environment prior to evaluating the script:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ReadFile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;my-file.ucl&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;inst&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ucl&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;New&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;inst&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Eval&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;bytes&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewReader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;ucl&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WithSubEnv&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Under the hood, this forks the top-level environment frame and marks it as the frame to store all procs and global variables for the evaluated file. This effectively makes it a separate namespace, separating it from all other scripts and preventing cross-contamination when scripts share the same symbol.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m hoping that this will eventually be the basis for UCL modules, but for now, this is use within Dynamo-Browse to isolate each UCL extension. The downside of this is that it&amp;rsquo;s no longer possible to add new commands simply using the &lt;code&gt;proc&lt;/code&gt; keyword. I think this may end up being a good thing though, as extensions will probably not be interested in exposing internal functions defined just for their own use.&lt;/p&gt;
&lt;p&gt;To compensate for this, there is now a new command — &lt;code&gt;ui:command&lt;/code&gt; — which allows the script author to expose a function as a command. In fact, what it does is save the command in the root environment frame, effectively making it work the old way &lt;code&gt;proc&lt;/code&gt; did, and acting like a poor-mans extension export.&lt;/p&gt;
&lt;p&gt;Now with all the extension loading in place, it&amp;rsquo;s time for the inaugural UCL extension. Here it is:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# Gets the partition key of the currently selected row, and adds it
# to the pasteboard. Bound to the &amp;#39;U&amp;#39; key.

ui:command copy-pk {
    # Get the partition key value from the currently selected item
    $pkKey = @table.Keys.PK
    $pkValue = @item.($pkKey)

    # Place it in the pasteboard
    pb:put $pkValue

    echo &amp;#34;$pkKey copied to clipboard&amp;#34;
}

ui:bind &amp;#34;U&amp;#34; { copy-pk }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;All the features are not quite implemented yet, but I think it&amp;rsquo;s good enough to start using it as part of my normal workflow. That&amp;rsquo;s usually the best way to find the rough edges.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/05/18/all-the-recent-changes-to.html</link>
      <pubDate>Sun, 18 May 2025 15:07:39 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2025/05/18/all-the-recent-changes-to.html</guid>
      <description>&lt;p&gt;All the recent changes to UCL is in service of unifying the scripting within Dynamo Browse. Right now there are two scripting languages: one for the commands entered after pressing  &lt;code&gt;:&lt;/code&gt;, and one for extensions. I want to replace both of them with UCL, which will power both interactive commands, and extensions.&lt;/p&gt;
&lt;p&gt;Most of the commands used within the in-app REPL loop has been implemented in UCL. I&amp;rsquo;m now in the process of building out the UCL extension support, start with functions for working with result sets, and pseudo-variables for modifying elements of the UI.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a demo of what I&amp;rsquo;ve got so far. This shows the user&amp;rsquo;s ability to control the current result-set, and the selected item programatically. Even after these early changes, I&amp;rsquo;m already seeing much better support for doing such things than what was there before.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/videos/2025/dynamo-browse-pvals-demo.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Devlog: UCL — Assignment</title>
      <link>https://lmika.org/2025/05/18/devlog-ucl-assignment.html</link>
      <pubDate>Sun, 18 May 2025 10:35:57 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2025/05/18/devlog-ucl-assignment.html</guid>
      <description>&lt;p&gt;Toying with changing how assignment works in UCL. Up to now, assigning a variable to a value involved calling the &lt;code&gt;set&lt;/code&gt; command, which took a variable name, and the value to assign:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;set a &amp;#34;hello&amp;#34;
$a
--&amp;gt; &amp;#34;hello&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This has been fine, but I&amp;rsquo;m now running into few limitations with this approach. The first is that it doesn’t support setting subscript values within lists or values. Because &lt;code&gt;set&lt;/code&gt; is just a regular command, the parser will evaluate any dot or sub-pipe expressions prior to invoking &lt;code&gt;set&lt;/code&gt;. One way around this is to quoted the variable to assign as a string:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;set list [1 2 3]
set &amp;#34;$list.(1)&amp;#34; 4
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But this looks ugly, and will involve another pass of the parser every time &lt;code&gt;set&lt;/code&gt; is called.&lt;/p&gt;
&lt;p&gt;Another approach is converting &lt;code&gt;set&lt;/code&gt; to a macro, which receives the arguments as the parse tree. This gives &lt;code&gt;set&lt;/code&gt; more control over how to interpret the arguments. But it doesn&amp;rsquo;t resolve the second issue, which is an inconsistency introduced with a new feature I&amp;rsquo;m planning.&lt;/p&gt;
&lt;p&gt;I want to add the notion of pseudo variables, which act like regular variables except that getting or setting them will invoke some hander logic from the embedding system, rather than set a value in memory. Think of them similar to how &lt;code&gt;document&lt;/code&gt; and &lt;code&gt;window&lt;/code&gt; work in a browser&amp;rsquo;s JavaScript runtime. My plan for them is to embed this Dynamo Browse to allow the user to access or modify the result-set or selected item, which will result in the UI changing. I&amp;rsquo;m sure I&amp;rsquo;ll have more to say about that in the future.&lt;/p&gt;
&lt;p&gt;To distinguish them from normal variables, they&amp;rsquo;ll have an at-sign instead of a dollar sign:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;@value
--&amp;gt; something
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But as far as the user is concerned, they should act just like normal variables. And just like normal variables, they should be modifiable using the &lt;code&gt;set&lt;/code&gt; command. I don&amp;rsquo;t want the variable and pseudo-variable to share the same namespace (since they look different, there&amp;rsquo;s no reason for them to share one), so I needed a way to distinguish  between setting a pseudo-variable from a regular variable.&lt;/p&gt;
&lt;p&gt;This first means they needed to be quoted but I hacked a quick version of &lt;code&gt;set&lt;/code&gt; on this feature branch to
support setting them:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;set &amp;#34;@value&amp;#34; &amp;#34;new value&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But compare this with the first example. Notice that when we were setting &lt;code&gt;a&lt;/code&gt;, we didn&amp;rsquo;t need to include the dollar sign. Here we have a case where one sort of variable requires the prefix symbol, and the other doesn&amp;rsquo;t. This form of inconsistency was not appealing to me.&lt;/p&gt;
&lt;p&gt;Since the various modes of assignments has outgrown the ability of one command to do it all, I’ve decided to remove &lt;code&gt;set&lt;/code&gt; and add basic assignments to the language. These look like typical assignments you see in most other languages:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$a = &amp;#34;hello&amp;#34;
$a
--&amp;gt; &amp;#34;hello&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But they’ll be able to fix the issues from using &lt;code&gt;set&lt;/code&gt;, such as assign the value of subsets and showing consistent representation of what you&amp;rsquo;re actually trying to modify:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;@value = &amp;#34;new value&amp;#34;

$list = [1 2 3]
$list.(1) = 4
$list
--&amp;gt; [1 4 3]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It also leads to some improvements of the common case. One small issue with using &lt;code&gt;set&lt;/code&gt; is that it always required one to wrap the result of a sub-expression in parenthesis.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;set h (strs:to-upper &amp;#34;Hello&amp;#34;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But since this is a grammar change, these parenthesis are no longer necessary.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$h = strs:to-upper &amp;#34;Hello&amp;#34;

$h = &amp;#34;Hello&amp;#34; | strs:to-upper
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There may also be room for different forms of assignment, such as ensuring the value you&amp;rsquo;re trying to set is not nil. There was a variant of set, called &lt;code&gt;set!&lt;/code&gt;, which threw an error when attempting to assign a variable to nil. This could be expressed as a different assignment form:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$h = &amp;#34;this is fine&amp;#34;

$h =! ()
--&amp;gt; error: trying to set $h to a nil value
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I will acknowledge that doing this will mean loosing out on some theoretical benefits that came from using &lt;code&gt;set&lt;/code&gt;.  For one thing, it will no longer be possible to indirectly set a value. You can&amp;rsquo;t, for example, do this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;set b &amp;#34;a&amp;#34;
set $b &amp;#34;hello&amp;#34;
$a
--&amp;gt; &amp;#34;hello&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I&amp;rsquo;ve never really needed to do this, but I could see this being potentially useful. One way to support this might be to &lt;a href=&#34;https://lua.org/manual/5.4/manual.html#2.2&#34;&gt;do something similar to what Lua does&lt;/a&gt;, and expose the environment as a hash. Pseudo-variables could be useful here:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$b = &amp;#34;a&amp;#34;
@_G.($b) = &amp;#34;hello&amp;#34;
$a
--&amp;gt; &amp;#34;hello&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I&amp;rsquo;ll hold off from adding something like this until I absolutely need to.&lt;/p&gt;
&lt;p&gt;So that&amp;rsquo;s the current idea. I spent around an hour on this so far, just trying it out and seeing how it feels, and I think it&amp;rsquo;s got promise. I&amp;rsquo;ll keep it on the feature branch for now, but I suspect this will eventually become the new way to do assignment in UCL going forward.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/03/21/one-of-the-tools-i.html</link>
      <pubDate>Fri, 21 Mar 2025 12:36:03 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2025/03/21/one-of-the-tools-i.html</guid>
      <description>&lt;p&gt;One of the tools I built for work is starting to get more users, so I probably should remove UCL and replace it with a &amp;ldquo;real&amp;rdquo; command language. That&amp;rsquo;s the risk of building something for yourself: if it&amp;rsquo;s useful, others will want to use it.&lt;/p&gt;
&lt;p&gt;I will miss using UCL, if I do have to remove it. Integrating another command language like TCL or Lisp is not easy, mainly because it&amp;rsquo;s difficult to map my domain to what the language supports. Other languages, like Lua or Python, map more nicely, but they&amp;rsquo;re awful to use as a command language. Sure, they may have REPLs, but dealing with the syntax is not fun when you&amp;rsquo;re just trying to get something done. That&amp;rsquo;s why I built UCL: to be useable in a REPL, yet rich enough to operate over structured data in a not-crappy way (it may not be glamorous, but it should be doing), while easy to integrate within a Go application.&lt;/p&gt;
&lt;p&gt;Of course, if I want to continue to use it, it needs some effort put into it, such as documentation. So which one do I want more?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/02/20/have-technically-secured-user-no.html</link>
      <pubDate>Thu, 20 Feb 2025 21:48:41 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2025/02/20/have-technically-secured-user-no.html</guid>
      <description>&lt;p&gt;Have technically secured user no. 2 of UCL today, after sharing one of the tools that&amp;rsquo;s using the language with them at work. It&amp;rsquo;s just a shame that the docs are so far behind (read: not existent). All I really have are &lt;a href=&#34;https://lmika.org/categories/ucl/&#34;&gt;these blog posts&lt;/a&gt; about building it. Good thing he&amp;rsquo;s a reader 😛. (Hi, KK).&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/02/08/moving-all-my-project-posts.html</link>
      <pubDate>Sat, 08 Feb 2025 12:29:07 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2025/02/08/moving-all-my-project-posts.html</guid>
      <description>&lt;p&gt;Moving all my project posts onto a separate blog… again. I tried writing them here, but I still feel like they belong elsewhere, where I have a bit more control over the layout and the design. Spent the morning configuring the theme, which was going to be orange but I had to change it to red as the orange didn&amp;rsquo;t provide a nice contrast for reading (you had to darken it almost to brown). I&amp;rsquo;m not sure if I&amp;rsquo;ll move the old posts over to it yet. Maybe the one&amp;rsquo;s on UCL.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update on 14/2:&lt;/strong&gt; No, changed my mind again. See &lt;a href=&#34;https://lmika.org/2025/02/14/kind-of-wish-i-can.html&#34;&gt;this post&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>UCL: Some Updates</title>
      <link>https://lmika.org/2025/02/08/ucl-some-updates.html</link>
      <pubDate>Sat, 08 Feb 2025 10:32:00 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2025/02/08/ucl-some-updates.html</guid>
      <description>&lt;p&gt;Made a few minor changes to UCL. Well, actually, I made one large change. I&amp;rsquo;ve renamed the &lt;code&gt;foreach&lt;/code&gt; builtin to &lt;code&gt;for&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I was originally planning to have a &lt;code&gt;for&lt;/code&gt; loop that worked much like other languages: you have a variable, a start value, and an end value, and you&amp;rsquo;d just iterate over the loop until you reach the end.  I don&amp;rsquo;t know how this would&amp;rsquo;ve looked, but I imagined something like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;for x 0 10 {
    echo $x
}
# numbers 0..9 would be printed.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But this became redundant after adding the &lt;code&gt;seq&lt;/code&gt; builtin:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;foreach (seq 10) { |x|
    echo $x
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This was in addition to all the other useful things you could do with the foreach loop&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, such as loop over lists and hashes, and consume values from iterators. It&amp;rsquo;s already a pretty versatile loop. So I elected to go the Python way and just made it so that the &lt;code&gt;for&lt;/code&gt; loop is the loop to use to iterate over collections.&lt;/p&gt;
&lt;p&gt;This left an opening for a loop that dealt with guards, so I also added the &lt;code&gt;while&lt;/code&gt; loop. Again, much like most languages, this loop would iterate over a block until the guard becomes false:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;set x 0
while (lt $x 5) {
    echo $x
    set x (add $x 1)
}
echo &amp;#34;done&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Unlike the &lt;code&gt;for&lt;/code&gt; loop, this is unusable in a pipeline (well, unless it&amp;rsquo;s the first component). I was considering having the loop return the result of the guard when it terminates, but I realised that would be either false, nil, or anything else that was &amp;ldquo;falsy.&amp;rdquo; So I just have the loop return nil. That said, you can break from this loop, and if the break call had a value, that would be used as the result of the loop:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;set x 0
while (lt $x 5) {
    set x (add $x 1)
    if (ge $x 3) {
        break &amp;#34;Ahh&amp;#34;
    }
} | echo &amp;#34; was the break&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The guard is optional, and if left out, the &lt;code&gt;while&lt;/code&gt; loop will iterate for ever.&lt;/p&gt;
&lt;h2 id=&#34;the-set-builtin&#34;&gt;The Set! Builtin&lt;/h2&gt;
&lt;p&gt;Many of these changes come from using of UCL for my job, and one thing I found myself doing recently is writing a bunch of migration scripts. This needed to get data from a database, which may or may not be present. If it&amp;rsquo;s not, I want the script to fail immediately so I can check my assumptions.  This usually results in constructs like the following:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;set planID (ls-plans | first { |p| eq $p &amp;#34;Plan Name&amp;#34; } | index ID)
if (not $planID) {
    error &amp;#34;cannot find plan&amp;#34;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And yeah, adding the if block is fine — I do it all the time when writing Go — but it would be nice to assert this when you&amp;rsquo;re trying to set the variable, for no reason other than the fact that you&amp;rsquo;re thinking about nullability while writing the expression to fetch the data.&lt;/p&gt;
&lt;p&gt;So one other change I made was add the &lt;code&gt;set!&lt;/code&gt; builtin. This will basically set the variable only if the expression is not nil. Otherwise, it will raise an error.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;set! planID (ls-plans | first { |p| eq $p &amp;#34;Missing Plan&amp;#34; } | index ID)
# refusing to set! `planID` to nil value
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This does mean that &lt;code&gt;!&lt;/code&gt; and &lt;code&gt;?&lt;/code&gt; are now valid characters to appear in identifiers, just like Ruby. I haven&amp;rsquo;t decided whether I want to start following the Ruby convention of question marks indicating a predicate or bangs indicating a mutation. Not sure that&amp;rsquo;s going to work out now, given that the bang is being used here to assert non-nullability.  In either case, could be useful in the future.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;And the &lt;code&gt;seq&lt;/code&gt; builtin&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Idea for UCL: Methods </title>
      <link>https://lmika.org/2025/02/02/idea-for-ucl-methods.html</link>
      <pubDate>Sun, 02 Feb 2025 15:46:00 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2025/02/02/idea-for-ucl-methods.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;m toying with the idea of adding methods to UCL. This will be similar to the methods that exist in Lua, in that they&amp;rsquo;re essentially functions that pass in the receiver as the first argument, although methods would only be definable by the native layer for the first version.&lt;/p&gt;
&lt;p&gt;Much like Lua though, methods would be invokable using the &lt;code&gt;:&lt;/code&gt; &amp;ldquo;pair&amp;rdquo; operator.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;strs:to-upper &amp;#34;Hello&amp;#34;
--&amp;gt; HELLO
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The idea is to make some of these methods on the types themselves, allowing their use on literals and the result of pipelines, as well as variables:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;set h &amp;#34;Hello&amp;#34;
$hello:to-upper
--&amp;gt; HELLO

&amp;#34;Hello&amp;#34;:to-upper
--&amp;gt; HELLO

(cat &amp;#34;Hello &amp;#34; &amp;#34;world&amp;#34;):to-upper
--&amp;gt; HELLO WORLD
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The use of methods would be purely conveience. One could conceive of a type, like a CSV table, where there&amp;rsquo;s a need to perform a series of operations over it.&lt;/p&gt;
&lt;p&gt;The potential downside of using &lt;code&gt;:&lt;/code&gt; is that it may make defining dictionaries more ambiguous. When the parser sees something that could either be a list or a dictionary, it does a scan to search for any pairs that may exist. If so, it treats the literal as a dictionary. But would this work with using &lt;code&gt;:&lt;/code&gt; as the method separator?&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[&amp;#34;Hello&amp;#34;:to-upper]
--&amp;gt; Is this a dictionary {&amp;#34;Hello&amp;#34;:&amp;#34;to-upper&amp;#34;}, or the list [&amp;#34;HELLO&amp;#34;]?
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So that would require something. Might be that I need to require method invocations to occur within parenthesis for list literals.&lt;/p&gt;
&lt;p&gt;Ambiguities like this aside, I&amp;rsquo;m planning to keep it simple for now. Methods will not be user definable within UCL out of the gate, but would be effectively another interface available to native types. For the builtin ones that exist now, it&amp;rsquo;ll most likely be little more than syntactic sugar over the standard library functions:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$hello:to-upper

# equivalent to

strs:to-upper $hello
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Speaking of the standard library, the use of &lt;code&gt;:&lt;/code&gt; as a module-function separator may need some changes. A the moment it&amp;rsquo;s a bit of a hack: when a module is loaded, any procs defined within that module is stored in the environment with the operator: &lt;code&gt;strs:to-upper&lt;/code&gt; for example. The parser is sophisticated enough to recognised &lt;code&gt;:&lt;/code&gt; as a token, but when it parses two or more identifiers separated with &lt;code&gt;:&lt;/code&gt;, it just joins them up into a single identifier.&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s needed is something else, maybe using something based on methods. The current idea is to define modules as being some special form of object, where the &amp;ldquo;methods&amp;rdquo; are simply the names of the exported symbol.&lt;/p&gt;
&lt;p&gt;I was curious to know whether the language was capable of doing something similar now. It&amp;rsquo;s conceivable that a similar concept could be drafted with procs returning dictionaries of procs, effectively acting as a namespace for a collection of functions.  So a bit of time in the playground resulted in this experiment:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;proc fns {
  return [
    upper: (proc { |x| strs:to-upper $x })
    lower: (proc { |x| strs:to-lower $x })
  ]
}

(fns).upper &amp;#34;Hello&amp;#34;
--&amp;gt; HELLO

(fns).lower &amp;#34;Hello&amp;#34;
--&amp;gt; hello
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A good first start. This is theoretically possible in the language that exists at the moment. It&amp;rsquo;s not perfect thought. For one thing, the call to &lt;code&gt;fns&lt;/code&gt; needs to be enclosed in parenthesis in order to invoke it. Leaving them out results in an error:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;fns.upper &amp;#34;Hello&amp;#34;
--&amp;gt; error: command is not invokable
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The same is true when using variables instead of procs. I tried this experiment again using variables and it came to the same limitations:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;set fns [
  upper: (proc { |x| strs:to-upper $x })
  lower: (proc { |x| strs:to-lower $x })
]

($fns).upper &amp;#34;Hello&amp;#34;
--&amp;gt; HELLO

$fns.upper &amp;#34;Hello&amp;#34;
--&amp;gt; error: command is not invokable
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Obviously the parser needs to be changed to add additional support for the &lt;code&gt;:&lt;/code&gt; operator, but I also need to fix how strong &lt;code&gt;.&lt;/code&gt; binds to values too.  But I think this may have legs.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>UCL: Iterators</title>
      <link>https://lmika.org/2025/01/31/still-working-on-ucl-in.html</link>
      <pubDate>Fri, 31 Jan 2025 09:41:44 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2025/01/31/still-working-on-ucl-in.html</guid>
      <description>&lt;p&gt;Still working on UCL in my spare time, mainly filling out the standard library a little, like adding utility functions for lists and CSV files. Largest change made recently was the adding iterators to the mix of core types. These worked a lot like the streams of old, where you had a potentially unbounded source of values that could only be consumed one at a time. The difference with streams is that there is not magic to this: iterators work like any other type, so they could be stored in variables, passed around methods, etc (streams could only be consumed via pipes).&lt;/p&gt;
&lt;p&gt;I augmented the existing high-level functions like &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt; to consume and produce iterators, but it was fun discovering other functions which also became useful. For example, there exists a &lt;code&gt;head&lt;/code&gt; function which returned the first value of a list. But I discovered that the semantics also worked as a way to consume the next element from an iterator. So that’s what this function now does. This, mixed with the fact that iterators are truthy if they’re got at least one pending value, means that some of the builtins could now be implemented in UCL itself. Like the example below, which could potentially be used to reimplement &lt;code&gt;itrs:to-list&lt;/code&gt; (this is a contrived example, as &lt;code&gt;foreach&lt;/code&gt; would probably work better here).&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;proc to-list { |itr lst|
   if $itr {
      lists:add $lst (head $itr)
      return (to-list $itr $lst)
   }
   return $lst
}

to-list (itrs:from [1 2 3 4 5]) []
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But the biggest advantage that comes from iterators is querying large data-stores with millions of rows. Being able to write a UCL script which sets up a pipeline of &lt;code&gt;maps&lt;/code&gt; and &lt;code&gt;filters&lt;/code&gt; and just let it churn through all the data in it&amp;rsquo;s own time is the dream.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;list-customers | filter { |x| $x.HasPlan } | map { |x| $x.PlanID } | foreach echo
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I&amp;rsquo;ve got a need for this in the internal backend tool that spurred the development of UCL, and I&amp;rsquo;m looking forward to using iterators to help here.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/01/19/started-filling-out-the-ucl.html</link>
      <pubDate>Sun, 19 Jan 2025 10:24:18 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2025/01/19/started-filling-out-the-ucl.html</guid>
      <description>&lt;p&gt;Started filling out the &lt;a href=&#34;https://ucl.lmika.dev/&#34;&gt;UCL website&lt;/a&gt;, mainly by documenting the core modules. It might be a little unnecessary to have a full website for this, given that the only person who&amp;rsquo;ll get any use from it right now will be myself. But who knows how useful it could be in the future? If nothing else, it&amp;rsquo;s a showcase on what I&amp;rsquo;ve been working on for this project.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/01/15/ive-been-using-ucl-a.html</link>
      <pubDate>Wed, 15 Jan 2025 22:40:42 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2025/01/15/ive-been-using-ucl-a.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been using UCL a lot recently, which is driving additional development on it. Spent a fair bit of time this evening fixing bugs and adding small features like string interpolation. Fix a number of grammar bugs too, that only popped up when I started writing multi-line scripts with it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/12/12/i-plan-to.html</link>
      <pubDate>Thu, 12 Dec 2024 08:48:00 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2024/12/12/i-plan-to.html</guid>
      <description>&lt;p&gt;I plan to integrate &lt;a href=&#34;https://workpad.dev/categories/tcl&#34;&gt;UCL&lt;/a&gt; into another tool at work, so I spent last night improving it&amp;rsquo;s use as a REPL. Added support for onboard help and setting up custom type printing, which is useful for displaying tables of data. I started working on the tool today and it&amp;rsquo;s already feeling great.&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/out-20241212-084242.png&#34; width=&#34;600&#34; height=&#34;465&#34; alt=&#34;A command line interface is displayed, showing help-related commands, usage, arguments, and details.&#34;&gt;
</description>
    </item>
    
    <item>
      <title>Weekly Update - 3 Nov 2024</title>
      <link>https://lmika.org/2024/11/03/weekly-update-nov.html</link>
      <pubDate>Sun, 03 Nov 2024 21:39:41 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2024/11/03/weekly-update-nov.html</guid>
      <description>&lt;p&gt;I probably should stop calling these &amp;ldquo;weekly updates,&amp;rdquo; seeing that
they come up a lot less frequently than once a week. Maybe I should
switch to something like &amp;ldquo;Sunday updates,&amp;rdquo; or maybe something closer
to what this is, which is an excuse to procrastinate by writing about
what I&amp;rsquo;ve been working on, rather than just working on it.&lt;/p&gt;
&lt;p&gt;But I&amp;rsquo;m sure you&amp;rsquo;re not interested in my willowing about the frequency
of these updates, so let&amp;rsquo;s just get straight to the meat of it.&lt;/p&gt;
&lt;h2 id=&#34;cyber-burger&#34;&gt;Cyber Burger&lt;/h2&gt;
&lt;p&gt;All the logic, graphics, and sound-effects for power-up/power-downs are
now finished. They now spawn in randomly, with a frequency and specific
types dictated by the current stage. I also added the notion of a
&amp;ldquo;milkshake bonus&amp;rdquo; which awards the player a bonus multiplier for a
short amount of time.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve also made a few balancing changes around demerits. Based on my own
testing, I was pretty blasé about loosing demerits, as you could recover
a demerit every time you finish a burger. I wanted to discourage that,
so I changed things around a little. You still loose demerits if you
screw up the burger your trying to build — such as making it too high or
not catching the correct item — but you no longer recover demerits for
every burger you complete. Instead, you recover one demerit for every
$50 you&amp;rsquo;re awarded. This is now every three to four burgers, depending
on how sophisticated they are, which I hope would make loosing demerits
something the player would want to avoid.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s still the difficulty curve stuff left to do, but I think I&amp;rsquo;ll
start working on the meta elements, like the title screen, main menu and
high score tables. I can probably leave out the addition of stages and a
difficulty curve if I&amp;rsquo;m honest, but I would like to have a decent title
and menu screen.&lt;/p&gt;
&lt;p&gt;The other thing to do is write the manual. I made a start the other day,
but there&amp;rsquo;s much left to do on this front. Part of me wonders whether
it make sense adding &amp;ldquo;on-board documentation.&amp;rdquo;  But part of the fun of
using Pico-8 on this project is to imagine a time where this game came
out during the late 70&amp;rsquo;s and early 80&amp;rsquo;s and the 8-bit era of home
consoles. And &lt;em&gt;those&lt;/em&gt; games didn&amp;rsquo;t have on-board documentation. That
said, I might add a quick start guide for those that didn&amp;rsquo;t RTFM.&lt;/p&gt;
&lt;h2 id=&#34;ucl&#34;&gt;UCL&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve been using that tool I&amp;rsquo;ve written for work quite often so there
was a need to add some additional features to UCL. The biggest one was
adding exceptions, but there&amp;rsquo;ve been a lot of little things like
rounding out the standard library.&lt;/p&gt;
&lt;p&gt;All the code written in a rush is starting to weigh this project down
though, and I do think I&amp;rsquo;ll need to do some refactoring to tidy things
up a little. I may need to work on documentation too, just for my own
sake more than anything else. I doubt this would be anything more than
the toy language it currently is, but it does have it&amp;rsquo;s uses, and
whenever I need to reference a built-in, I&amp;rsquo;m always going to the source
code. Which is fine, but I think I can do better on this front.&lt;/p&gt;
&lt;h2 id=&#34;other-projects&#34;&gt;Other Projects&lt;/h2&gt;
&lt;p&gt;A few other things I worked on during the last fortnight:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I spent some time last weekend playing with Htmgo by making a simple
world clock that would update every second. I ended up remaking this
as a &lt;a href=&#34;https://clocks.lmika.app/&#34;&gt;static web page&lt;/a&gt; backed by some WASM code. Knowing the time
in UTC and some American cities could come in handy for my job. At
least, that&amp;rsquo;s the theory: I haven&amp;rsquo;t had a need for it yet.&lt;/li&gt;
&lt;li&gt;I also made some changes to Nano Journal to add support for uploading
multiple attachments at once.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So that&amp;rsquo;s the update for this past fortnight.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Try-Catch In UCL - Some Notes</title>
      <link>https://lmika.org/2024/10/21/trycatch-in-ucl.html</link>
      <pubDate>Mon, 21 Oct 2024 16:49:09 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2024/10/21/trycatch-in-ucl.html</guid>
      <description>&lt;p&gt;Stared working on a &lt;code&gt;try&lt;/code&gt; command to UCL, which can be used to trap
errors that occur within a block. This is very much inspired by
try-blocks in Java and Python, where the main block will run, and if any
error occurs, it will fall through to the catch block:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;try {
  echo &amp;quot;Something bad can happen here&amp;quot;
} catch {
  echo &amp;quot;It&#39;s all right. I&#39;ll run next&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is all I&amp;rsquo;ve got working at the moment, but I want to quickly write
some notes on how I&amp;rsquo;d like this to work, lest I forget it later.&lt;/p&gt;
&lt;p&gt;First, much like everything in UCL, these blocks should return a value.
So it should be possible to do something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set myResults (try {
  result-of-something-that-can-fail
} catch {
  &amp;quot;My default&amp;quot;
})
--&amp;gt; (result of the thing)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is kind of like using &lt;code&gt;or&lt;/code&gt; in Lua to fallback to a default, just
that if the result fails with an error, the default value can be
returned from the &lt;code&gt;catch&lt;/code&gt; block. In might even be possible to simply
this further, and have &lt;code&gt;catch&lt;/code&gt; just return a value in cases where an
actual block of code is unnecessary:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set myResults (try { result-of-something-that-can-fail } catch &amp;quot;My default&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One other thing to consider is how to represent the error.  Errors are
just treated out-of-band at the moment, and are represented as regular
Go &lt;code&gt;error&lt;/code&gt; types. It might be necessary to add a new &lt;code&gt;error&lt;/code&gt; type to
UCL, so that it can be passed through to the &lt;code&gt;catch&lt;/code&gt; block for logging
or switching:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;try {
  do-something
} catch { |e|
  echo (cat &amp;quot;The error is &amp;quot; $e)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This could also be used as the return value if there is no &lt;code&gt;catch&lt;/code&gt;
block:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set myResult (try { error &amp;quot;my error&amp;quot; })
--&amp;gt; error: my error
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another idea I have is successive catch blocks, that would cascade one
after the other if the one before it fails:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;try {
  do-something
} catch {
  this-may-fail-also
} catch {
  echo &amp;quot;Always passes&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unlike JavaScript or Python, I don&amp;rsquo;t think the idea of having &lt;code&gt;catch&lt;/code&gt;
blocks switching based on the error type would be suitable here. UCL is
dynamic in nature, and having this static type checking feels a little
wrong here. The &lt;code&gt;catch&lt;/code&gt; blocks will only act as isolated blocks of
execution, where an error would be caught and handled.&lt;/p&gt;
&lt;p&gt;Finally, there&amp;rsquo;s &lt;code&gt;finally&lt;/code&gt;, which would run regardless of which try or
catch block was executed. I think, unlike the other two blocks, that the
return value of a &lt;code&gt;finally&lt;/code&gt; block will always be swallowed. I think this
will work as the finally block should mainly be used for clean-up, and
it&amp;rsquo;s the result of the &lt;code&gt;try&lt;/code&gt; or &lt;code&gt;catch&lt;/code&gt; blocks that are more important.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set res (try {
  &amp;quot;try&amp;quot;
} catch {
  &amp;quot;catch&amp;quot;
} finally {  
  &amp;quot;finally&amp;quot;
})
--&amp;gt; &amp;quot;try&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Anyway, this is the idea I have right now.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update —&lt;/strong&gt; I just realised that the idea of the last successful try
block return an error, rather than letting it climb up the stack defeats
the purpose of exceptions. So having something like the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;try { error &amp;quot;this will fail&amp;quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Should just unroll the stack and not return an error value. Although if
there is a need to have an error value returned, then the following
should work:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;try { error &amp;quot;this will fail&amp;quot; } catch { |err| $err }
--&amp;gt; error: this will fail
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Project Updates</title>
      <link>https://lmika.org/2024/09/08/project-updates.html</link>
      <pubDate>Sun, 08 Sep 2024 18:14:51 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2024/09/08/project-updates.html</guid>
      <description>&lt;p&gt;Well, it&amp;rsquo;s been three weeks since my last post here, and as hard as it
was to write this update, not writing it would&amp;rsquo;ve been harder. So
let&amp;rsquo;s just skip the preamble and go straight to the update.&lt;/p&gt;
&lt;h2 id=&#34;cyber-burger-that-pico-8-game&#34;&gt;Cyber Burger (That Pico-8 Game)&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m terrible at being coy, I&amp;rsquo;ll just spill the beens. That game I&amp;rsquo;ve
been working on is call Cyber Burger. It&amp;rsquo;s based on a DOS game I saw on
YouTube, and it seemed like a fun project to try and work on, with some
tweaks to the gameplay that I think would make it more forgiving.&lt;/p&gt;
&lt;p&gt;In the weeks since my last update, I finished with the prototypes and
started working on the game itself. The initial set of art is done and a
very simple &amp;ldquo;Game A&amp;rdquo; mode has been implemented. In this mode, you are
shown a burger you&amp;rsquo;ll need to make in your basket. You do so by
shooting down the items flying across the screen and catching them in
order. When you do, you get a &amp;ldquo;tip&amp;rdquo;, which basically amounts to
points. If you make a mistake, you&amp;rsquo;re given a demerit. There are five
rounds in total, and once the round is complete, you move on to the next
one, with maybe slightly different items, or different item speeds,
etc.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/9041d44143.jpg&#34;&gt;
&lt;figcaption&gt;An example play session, with the new graphics.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I managed to make a HTML version of this which plays through round 1. I
gave it to someone at work to play test and the results were… well, they
weren&amp;rsquo;t bad but it didn&amp;rsquo;t set the world on fire.&lt;/p&gt;
&lt;p&gt;I think I&amp;rsquo;m okay with that, but I do need to keep working on it. I
think one thing that would help is adding sound. And I think it might
help me deliver this earlier if I abandoned Mode A and start working on
Mode B, which is closer to an arcade style of game that would allow for
continuous play. These two things, I&amp;rsquo;ll aim to work on this next week.&lt;/p&gt;
&lt;p&gt;Oh, and I&amp;rsquo;ll need to fix the item spawner. Waiting ages for an item you
need is no good.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re interested in giving it a try, you can do so by &lt;a href=&#34;https://cyberger.lmika.app&#34;&gt;following
this link&lt;/a&gt; (it runs in the browser). Feel free to &lt;a href=&#34;https://letterbird.co/lmika&#34;&gt;send any
feedback&lt;/a&gt; you may have.&lt;/p&gt;
&lt;h2 id=&#34;ucl&#34;&gt;UCL&lt;/h2&gt;
&lt;p&gt;The other thing I&amp;rsquo;ve been spending some time on over the last week or
so was UCL. I&amp;rsquo;ve been using that work tool which has this language
quite often recently and I&amp;rsquo;ve been running against a number of bugs and
areas where quality of life changes could be made. Just small things,
such as allowing the &lt;code&gt;foreach&lt;/code&gt; command to be called with a proc name
instead of requiring a block, much like the &lt;code&gt;map&lt;/code&gt; function. Those have
been addressed.&lt;/p&gt;
&lt;p&gt;But the biggest thing I&amp;rsquo;ve been worked on was building out the core
library. I added the following functions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The `seq` function, used for generating a sequence of integers. I
like how I built this: it&amp;rsquo;s effectively a virtual list — that can be
indexed, iterated over, or calculated the length of — but does not
take up linear space.&lt;/li&gt;
&lt;li&gt;Comparator functions, like `eq`, `ne`, `gt`, etc. plus settling
on a type system much like Python, where values are strongly type
(can&amp;rsquo;t compare ints to strings) but are also dynamic.&lt;/li&gt;
&lt;li&gt;Arithmetic functions, like `add`, `sub`, etc. which operate on
integers, and the `cat` function use to concatenate strings (these
functions do try to cohere values to the correct type)&lt;/li&gt;
&lt;li&gt;Logical functions, like `and`, `or`, and `not`.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Along with this, I&amp;rsquo;ve started working through the strings package,
which would add the various string functions you see, like trimming
whitespace, splitting, joining, etc. I&amp;rsquo;ve got trimming and converting
to upper and lower case, and my goal for next week is to add splitting
to and joining from string lists. Once that&amp;rsquo;s done I&amp;rsquo;ll probably put
this on the back-burner again so I can finish off Cyber Burger or work
on something else.&lt;/p&gt;
&lt;p&gt;Just a reminder that there&amp;rsquo;s also a &lt;a href=&#34;https://ucl.lmika.dev&#34;&gt;playground for this too&lt;/a&gt;,
although I apologise for the lack of documentation. I&amp;rsquo;ll need to get
onto that as well.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Indexing In UCL</title>
      <link>https://lmika.org/2024/05/10/indexing-in-ucl.html</link>
      <pubDate>Fri, 10 May 2024 12:09:46 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2024/05/10/indexing-in-ucl.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been thinking a little about how to support indexing in UCL, as in
getting elements from a list or keyed values from a map.  There already
exists an &lt;code&gt;index&lt;/code&gt; builtin that does this, but I&amp;rsquo;m wondering if this can
be, or even should be, supported in the language itself.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve reserved &lt;code&gt;.&lt;/code&gt; for this, and it&amp;rsquo;ll be relatively easy to make use
of it to get map fields. But I do have some concerns with supporting
list element dereferencing using square brackets. The big one being that
if I were to use square brackets the same way that many other languages
do, I suspect (although I haven&amp;rsquo;t confirmed) that it could lead to the
parser treating them as two separate list literals. This is because the
scanner ignores whitespace, and there&amp;rsquo;s no other syntactic indicators
to separate arguments to proc calls, like commas:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo $x[4]      --&amp;gt; echo $x [4]
echo [1 2 3][2] --&amp;gt; echo [1 2 3] [2]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So I&amp;rsquo;m not sure what to do here. I&amp;rsquo;d like to add support for &lt;code&gt;.&lt;/code&gt; for
map fields but it feels strange doing that just that and having nothing
for list elements.&lt;/p&gt;
&lt;p&gt;I can think of three ways to address this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do Nothing&lt;/strong&gt; — the first option is easy: don&amp;rsquo;t add any new syntax to
the language and just rely on the &lt;code&gt;index&lt;/code&gt; builtin. TCL does with
&lt;a href=&#34;https://www.tcl.tk/man/tcl8.4/TclCmd/lindex.htm&#34;&gt;lindex&lt;/a&gt;, as does Lisp with &lt;a href=&#34;https://www.lispworks.com/documentation/HyperSpec/Body/f_nth.htm#nth&#34;&gt;nth&lt;/a&gt;, so I&amp;rsquo;ll be in good company
here.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use Only The Dot&lt;/strong&gt; — the second option is to add support for the dot
and not the square brackets. This is what the Go templating language
does for keys of maps or structs fields. They also have an &lt;code&gt;index&lt;/code&gt;
builtin too, which will work with slice elements.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d probably do something similar but I may extend it to support index
elements. Getting the value of a field would be what you&amp;rsquo;d expect, but
to get the element of a list, the construct &lt;code&gt;.(x)&lt;/code&gt; can be used:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo $x.hello     \# returns the &amp;quot;hello&amp;quot; field
echo $x.(4)       \# returns the forth element of a list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One benefit of this could be that the &lt;code&gt;.(x)&lt;/code&gt; construct would itself be a
pipeline, meaning that string and calculated values could be used as
well:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo $x.(&amp;quot;hello&amp;quot;)
echo $x.($key)
echo $x.([1 2 3] | len)
echo $x.(&amp;quot;hello&amp;quot; | toUpper)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can probably get away with supporting this without changing the
scanner or compromising the language design too much. It would be nice
to add support for ditching the dot completely when using the
parenthesis, a.la. BASIC, but I&amp;rsquo;d probably run into the same issues as
with the square brackets if I did, so I think that&amp;rsquo;s out.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use Parenthesis To Be Explicit&lt;/strong&gt; — the last option is to use square
brackets, and modify the grammar slightly to only allow the use of
suffix expansion within parenthesis. That way, if you&amp;rsquo;d want to pass a
list element as an argument, you have to use parenthesis:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo ($x[4])       \# forth element of $x
echo $x[4]         \# $x, along with a list containing &amp;quot;4&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is what you&amp;rsquo;d see in more functional languages like Elm and I
think Haskell. I&amp;rsquo;ll have  see whether this could work with changes to
the scanner and parser if I were to go with this option. I think it may
be achievable, although I&amp;rsquo;m not sure how.&lt;/p&gt;
&lt;p&gt;An alternative way might be to go the other way, and modify the grammar
rules so that the square brackets would bind closer to the list, which
would mean that separate arguments involving square brackets would need
to be in parenthesis:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo $x[4]         \# forth element of $x
echo $x ([4])      \# $x, along with a list containing &amp;quot;4&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or I could modify the scanner to recognise whitespace characters and use
that as a guide to determine whether square brackets following a value.
At least one space means the square bracket represent a element suffix,
and zero mean two separate values.&lt;/p&gt;
&lt;p&gt;So that&amp;rsquo;s where I am at the moment. I guess it all comes down to what
works best for the language as whole. I can live with option one but it
would be nice to have the syntax. I rather not go with option three as
I&amp;rsquo;d like to keep the parser simple (I rather not add to all the
new-line complexities I&amp;rsquo;ve have already).&lt;/p&gt;
&lt;p&gt;Option two would probably be the least compromising to the design as a
whole, even if the aesthetics are a bit strange. I can probably get use
to them though, and I do like the idea of index elements being pipelines
themselves. I may give option two a try, and see how it goes.&lt;/p&gt;
&lt;p&gt;Anyway, more on this later.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Tape Playback Site</title>
      <link>https://lmika.org/2024/05/05/tape-playback-site.html</link>
      <pubDate>Sun, 05 May 2024 23:14:02 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2024/05/05/tape-playback-site.html</guid>
      <description>&lt;p&gt;Thought I&amp;rsquo;d take a little break from UCL today.&lt;/p&gt;
&lt;p&gt;Mum found a collection of old cassette tapes of us when we were kids,
making and recording songs and radio shows. I&amp;rsquo;ve been digitising them
over the last few weeks, and today the first recorded cassette was ready
to share with the family.&lt;/p&gt;
&lt;p&gt;I suppose I could&amp;rsquo;ve just given them raw MP3 files, but I wanted to
record each cassette as two large files — one per side — so as to not
loose much of the various crackles and clatters made when the tape
recorder was stopped and started. But I did want to catalogue the more
interesting points in the recording, and it would&amp;rsquo;ve been a bit &amp;ldquo;meh&amp;rdquo;
simply giving them to others as one long list of timestamps (simulating
the rewind/fast-forward seeking action would&amp;rsquo;ve been a step too far).&lt;/p&gt;
&lt;p&gt;Plus, simply emailing MP3 files wasn&amp;rsquo;t nearly as interesting as what I
did do, which was  to put together a private site where others could
browse and play the recorded tapes:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/6b3473fe29.jpg&#34;&gt;
&lt;figcaption&gt;The landing page, listing the available tapes (of which there&#39;s only one right now.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/b7f3f993a8.jpg&#34;&gt;
&lt;figcaption&gt;Playback of a tape side, with chapter links for seeking.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The site is not much to talk about — it&amp;rsquo;s a Hugo site using the
&lt;a href=&#34;https://themes.gohugo.io/themes/mainroad/&#34;&gt;Mainroad theme&lt;/a&gt; and deployed to Netlify. There is some JavaScript
that moves the playhead when a chapter link is clicked, but the rest is
just HTML and CSS. But I did want to talk about how I got the audio
files into Netlify. I wanted to use `git lfs` for this and have
Netlify fetch them when building the site. Netlify doesn&amp;rsquo;t do this by
default, and I get the sense that Netlify&amp;rsquo;s support for LFS is somewhat
deprecated. Nevertheless, I gave it a try by adding an explicit `git
lfs` step in the build to fetch the audio files. And it could&amp;rsquo;ve been
that I was using the LFS command incorrectly, or maybe it was invoked at
the wrong time. But whatever the reason, the command errored out and the
audio files didn&amp;rsquo;t get pulled. I tried a few more times, and I probably
could&amp;rsquo;ve got it working if I stuck with it, but all those deprecation
warnings in Netlify&amp;rsquo;s documentation gave me pause.&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/33b0e90cfa.jpg&#34;&gt;
&lt;p&gt;So what I ended up doing was turning off builds in Netlify and using a
Github Action which built the Hugo site and publish it to Netlify using
the CLI tool. Here&amp;rsquo;s the Github Action in full:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Publish to Netify&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;on&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;push&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;branches&lt;/span&gt;: [&lt;span style=&#34;color:#ae81ff&#34;&gt;main]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;jobs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;build&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Build&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;runs-on&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;ubuntu-latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;steps&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;uses&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;actions/checkout@v4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;with&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;submodules&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;fetch-depth&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;lfs&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Setup Hugo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;uses&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;peaceiris/actions-hugo@v3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;with&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;hugo-version&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0.119.0&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Build Site&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;run&lt;/span&gt;: |&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          npm install
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          hugo&lt;/span&gt;          
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Deploy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;env&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;NETLIFY_SITE_ID&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${{ secrets.NETLIFY_SITE_ID }}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;NETLIFY_AUTH_TOKEN&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${{ secrets.NETLIFY_AUTH_TOKEN }}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;run&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;|          &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#ae81ff&#34;&gt;netlify deploy --dir=public --prod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This ended up working quite well: the audio files made it to Netlify and
were playable on the site. The builds are also quite fast; around 55
seconds (an earlier version involved building Hugo from source, which
took 5 minutes). So for anyone else interested in trying to serve LFS
files via Netlify, maybe try turning off the builds and going straight
to using Github Action and the CLI tool. That is… if you can swallow the
price of LFS storage in Github. Oof! A little pricy. Might be that I&amp;rsquo;ll
need to use something else for the audio files.&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>UCL: Brief Integration Update and Modules</title>
      <link>https://lmika.org/2024/05/04/ucl-brief-integration.html</link>
      <pubDate>Sat, 04 May 2024 22:14:27 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2024/05/04/ucl-brief-integration.html</guid>
      <description>&lt;p&gt;A brief update of where I am with UCL and integrating it into
Dynamo-browse. I did managed to get it integrated, and it&amp;rsquo;s now serving
as the interpreter of commands entered in during a session.&lt;/p&gt;
&lt;p&gt;It works… okay. I decided to avoid all the complexities I mentioned in
the last post — all that about continuations, etc. — and simply kept the
commands returning &lt;code&gt;tea.Msg&lt;/code&gt; values. The original idea was to have the
commands return usable values if they were invoked in a non-interactive
manner. For example, the &lt;code&gt;table&lt;/code&gt; command invoked in an interactive
session will bring up the table picker for the user to select the table.
But when invoked as part of a call to another command, maybe it would
return the current table name as a string, or something.&lt;/p&gt;
&lt;p&gt;But I decided to ignore all that and simply kept the commands as they
are. Maybe I&amp;rsquo;ll add support for this in a few commands down the line?
We&amp;rsquo;ll see. I guess it depends on whether it&amp;rsquo;s necessary.&lt;/p&gt;
&lt;p&gt;Which brings me up to why this is only working &amp;ldquo;okay&amp;rdquo; at the moment.
Some commands return a &lt;code&gt;tea.Msg&lt;/code&gt; which ask for some input from the user.
The &lt;code&gt;table&lt;/code&gt; command is one; another is &lt;code&gt;set-attr&lt;/code&gt;, which prompts the
user to enter an attribute value. These are implemented as a message
which commands the UI to go into an &amp;ldquo;input mode&amp;rdquo;, and will invoke a
callback on the message when the input is entered.&lt;/p&gt;
&lt;p&gt;This is not an issue for single commands, but it becomes one when you
start entering multiple commands that prompt for input, such as two
&lt;code&gt;set-attr&lt;/code&gt; calls:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set-attr this -S ; set-attr that -S
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What happens is that two messages to show the prompt are sent, but only
one of them is shown to the user, while the other is simply swallowed.&lt;/p&gt;
&lt;p&gt;Fixing this would require some re-engineering, either with how the
controllers returning these messages work, or the command handlers
themselves. I can probably live with this limitation for now — other
than this, the UCL integration is working well — but I may need to
revisit this down the line.&lt;/p&gt;
&lt;h2 id=&#34;modules&#34;&gt;Modules&lt;/h2&gt;
&lt;p&gt;As for UCL itself, I&amp;rsquo;ve started working on the builtins. I&amp;rsquo;m planning
to have a small set of core builtins for the most common stuff, and the
rest implemented in the form of &amp;ldquo;modules&amp;rdquo;. The idea is that the core
will most likely be available all the time, but the modules can be
turned on and off by the language embedder based on what they need or
are comfortable having.&lt;/p&gt;
&lt;p&gt;Each module is namespaces with a prefix, such as &lt;code&gt;os&lt;/code&gt; for operating
system operations, or &lt;code&gt;fs&lt;/code&gt; for file-system operations. I&amp;rsquo;ve chosen the
colon as the namespace separator, mainly so I can reserve the dot for
field dereferencing, but also because I think TCL uses the colon as a
namespace separator as well (I think I saw it in some sample code). The
first implementation of this was simply adding the colon to the list of
characters that make up the IDENT token. This broke the parser as the
colon is also use as the map key/value separator, and the parser
couldn&amp;rsquo;t resolve maps anymore. I had to extend the &amp;ldquo;indent&amp;rdquo; parse
rule to support multiple IDENT tokens separated by colons. The module
builtins are simply added to the environment with there fully-qualified
name, complete prefix and colon, and invoking them with one of these
idents will just &amp;ldquo;flatten&amp;rdquo; all these colon-separated tokens into a
single string. Not sophisticated, but it&amp;rsquo;ll work for now.&lt;/p&gt;
&lt;p&gt;There aren&amp;rsquo;t many builtins for these modules at the moment: just a few
for reading environment variables and getting files as list of strings.
Dynamo-browse is already using this in a feature branch, and it&amp;rsquo;s
allows me to finally add a long-standing feature I&amp;rsquo;ve been meaning to
add for a while: automatically enabling read-only mode when accessing
DynamoDB tables in production. With modules, this construct looks a
little like the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (eq (os:env &amp;quot;ENV&amp;quot;) &amp;quot;prod&amp;quot;) {
    set-opt ro
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It would&amp;rsquo;ve been possible to do this with the scripting language
already used by Dynamo-browse. But this is the motivation of integrating
UCL: it makes these sorts of constructs much easier to do, almost as one
would do writing a shell-script over something in C.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>UCL: Breaking And Continuation</title>
      <link>https://lmika.org/2024/05/01/ucl-breaking-and.html</link>
      <pubDate>Wed, 01 May 2024 09:01:36 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2024/04/30/ucl-breaking-and.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve started trying to integrate UCL into a second tool: Dynamo Browse.
And so far it&amp;rsquo;s proving to be a little difficult. The problem is that
this will be replacing a dumb string splitter, with command handlers
that are currently returning a &lt;a href=&#34;https://pkg.go.dev/github.com/charmbracelet/bubbletea#Msg&#34;&gt;tea.Msg&lt;/a&gt; type that change the UI in
some way.&lt;/p&gt;
&lt;p&gt;UCL builtin handlers return a &lt;code&gt;interface{}&lt;/code&gt; result, or an &lt;code&gt;error&lt;/code&gt;
result, so there&amp;rsquo;s no reason why this wouldn&amp;rsquo;t work. But &lt;code&gt;tea.Msg&lt;/code&gt; is
also an &lt;code&gt;interface{}&lt;/code&gt; types, so it will be difficult to tell a UI
message apart from a result that&amp;rsquo;s usable as data.&lt;/p&gt;
&lt;p&gt;This is a Dynamo Browse problem, but it&amp;rsquo;s still a problem I&amp;rsquo;ll need to
solve. It might be that I&amp;rsquo;ll need to return &lt;a href=&#34;https://pkg.go.dev/github.com/charmbracelet/bubbletea#Cmd&#34;&gt;tea.Cmd&lt;/a&gt; types — which
are functions returning &lt;code&gt;tea.Msg&lt;/code&gt; — and have the UCL caller detect these
and dispatch them when they&amp;rsquo;re returned. That&amp;rsquo;s a lot of function
closures, but it might be the only way around this (well, the
alternative is returning an interface type with a method that returns a
&lt;code&gt;tea.Msg&lt;/code&gt;, but that&amp;rsquo;ll mean a lot more types than I currently have).&lt;/p&gt;
&lt;p&gt;Anyway, more on this in the future I&amp;rsquo;m sure.&lt;/p&gt;
&lt;h2 id=&#34;break-continue-return&#34;&gt;Break, Continue, Return&lt;/h2&gt;
&lt;p&gt;As for language features, I realised that I never had anything to exit
early from a loop or proc. So I added &lt;code&gt;break&lt;/code&gt;, &lt;code&gt;continue&lt;/code&gt;, and &lt;code&gt;return&lt;/code&gt;
commands. They&amp;rsquo;re pretty much what you&amp;rsquo;d expect, except that &lt;code&gt;break&lt;/code&gt;
can optionally return a value, which will be used as the resulting value
of the &lt;code&gt;foreach&lt;/code&gt; loop that contains it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo (foreach [5 4 3 2 1] { |n|
  echo $n
  if (eq $n 3) {
    break &amp;quot;abort&amp;quot;
  }
})
--&amp;gt; 5
--&amp;gt; 4
--&amp;gt; 3
--&amp;gt; abort
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These are implemented as error types under the hood. For example,
&lt;code&gt;break&lt;/code&gt; will return an &lt;code&gt;errBreak&lt;/code&gt; type, which will flow up the chain
until it is handled by the &lt;code&gt;foreach&lt;/code&gt; command (&lt;code&gt;continue&lt;/code&gt; is also an
&lt;code&gt;errBreak&lt;/code&gt; with a flag indicating that it&amp;rsquo;s a continue). Similarly,
&lt;code&gt;return&lt;/code&gt; will return an &lt;code&gt;errReturn&lt;/code&gt; type that is handled by the &lt;code&gt;proc&lt;/code&gt;
object.&lt;/p&gt;
&lt;p&gt;This fits quite naturally with how the scripts are run. All I&amp;rsquo;m doing
is walking the tree, calling each AST node as a separate function call
and expecting it to return a result or an error. If an error is return,
the function bails, effectively unrolling the stack until the error is
handled or it&amp;rsquo;s returned as part of the call to &lt;code&gt;Eval()&lt;/code&gt;. So leveraging
this stack unroll process already in place makes sense to me.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not sure if this is considered idiomatic Go. I get the impression
that using error types to handle flow control outside of adverse
conditions is frowned upon. This reminds me of all the arguments against
using expressions for flow control in Java. Those arguments are good
ones: following executions between &lt;code&gt;try&lt;/code&gt; and &lt;code&gt;catch&lt;/code&gt; makes little sense
when the flow can be explained more clearly with an &lt;code&gt;if&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But I&amp;rsquo;m going to defend my use of errors here. Like most Go projects,
the code is already littered with all the &lt;code&gt;if err != nil { return err }&lt;/code&gt;
to exit early when a non-nil error is returned. And since Go developers
preach the idea of errors simply being values, why not use errors here
to unroll the stack? It&amp;rsquo;s better than the alternatives: such as
detecting a sentinel result type or adding a third return value which
will just be yet another &lt;code&gt;if bla { return res }&lt;/code&gt; clause.&lt;/p&gt;
&lt;h2 id=&#34;continuations&#34;&gt;Continuations&lt;/h2&gt;
&lt;p&gt;Now, an idea is brewing for a feature I&amp;rsquo;m calling &amp;ldquo;continuations&amp;rdquo;
that might be quite difficult to implement. I&amp;rsquo;d like to provide a way
for a user builtin to take a snapshot of the call stack, and resume
execution from that point at a later time.&lt;/p&gt;
&lt;p&gt;The reason for this is that I&amp;rsquo;d like all the asynchronous operations to
be transparent to the UCL user. Consider a UCL script with a &lt;code&gt;sleep&lt;/code&gt;
command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo &amp;quot;Wait here&amp;quot;
sleep 5
echo &amp;quot;Ok, ready&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;sleep&lt;/code&gt; could simply be a call to &lt;code&gt;time.Sleep()&lt;/code&gt; but say you&amp;rsquo;re running
this as part of an event loop, and you&amp;rsquo;d prefer to do something like
setup a timer instead of blocking the thread. You may want to hide this
from the UCL script author, so they don&amp;rsquo;t need to worry about
callbacks.&lt;/p&gt;
&lt;p&gt;Ideally, this can be implemented by the builtin using a construct
similar to the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func sleep(ctx context.Context, arg ucl.CallArgs) (any, error) {
  var secs int
  if err := arg.Bind(&amp;amp;secs); err != nil {
    return err
  }

  // Save the execution stack
  continuation := args.Continuation()

  // Schedule the sleep callback
  go func() {
    &amp;lt;- time.After(secs * time.Seconds)

    // Resume execution later, yielding `secs` as the return value
    // of the `sleep` call. This will run the &amp;quot;ok, ready&amp;quot; echo call
    continuation(ctx, secs)
  })()

  // Halt execution now
  return nil, ucl.ErrHalt
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The only trouble is, I&amp;rsquo;ve got no idea how I&amp;rsquo;m going to do this. As
mentioned above, UCL executes the script by walking the parse tree with
normal Go function calls. I don&amp;rsquo;t want to be in a position to create a
snapshot of the Go call stack. That a little too low level for what I
want to achieve here.&lt;/p&gt;
&lt;p&gt;I suppose I could store the visited nodes in a list when the &lt;code&gt;ErrHalt&lt;/code&gt;
is raised; or maybe replace the Go call stack with an in memory stack,
with AST node handlers being pushed and popped as the script runs. But
I&amp;rsquo;m not sure this will work either. It would require a significant
amount of reengineering, which I&amp;rsquo;m sure will be technically
interesting, but will take a fair bit of time. And how is this to work
if a continuation is made in a builtin that&amp;rsquo;s being called from another
builtin? What should happen if I were to run &lt;code&gt;sleep&lt;/code&gt; within a &lt;code&gt;map&lt;/code&gt;, for
example?&lt;/p&gt;
&lt;p&gt;So it might be that I&amp;rsquo;ll have to use something else here. I could
potentially do something using Goroutines: the script is executed on
Goroutine and &lt;code&gt;args.Continuation()&lt;/code&gt; does something like pauses it on a
channel. How that would work with a builtin handler requesting the
continuation not being paused themselves I&amp;rsquo;m not so sure. Maybe the
handlers could be dispatched on a separate Goroutine as well?&lt;/p&gt;
&lt;p&gt;A simpler approach might be to just offload this to the UCL user, and
have them run &lt;code&gt;Eval&lt;/code&gt; on a separate Goroutine and simply sleeping the
thread. Callbacks that need input from outside could simply be sent
using channels passed via the &lt;code&gt;context.Context&lt;/code&gt;. At least that&amp;rsquo;ll lean
into Go&amp;rsquo;s first party support for synchronisation, which is arguably a
good thing.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>UCL: The Simplifications Paid Off</title>
      <link>https://lmika.org/2024/04/26/ucl-the-simplifications.html</link>
      <pubDate>Fri, 26 Apr 2024 12:13:49 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2024/04/26/ucl-the-simplifications.html</guid>
      <description>&lt;p&gt;The UCL simplifications have been implemented, and they seem to be
largely successful.&lt;/p&gt;
&lt;p&gt;Ripped out all the streaming types, and changed pipes to simply pass the
result of the left command as first argument of the right.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;quot;Hello&amp;quot; | echo &amp;quot;, world&amp;quot;
--&amp;gt; &amp;quot;Hello, world&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This has dramatically improved the use of pipes. Previously, pipes could
only be used to connect streams. But now, with pretty much anything
flowing through a pipe, that list of commands has extended to pretty
much every builtins and user-defined procs. Furthermore, a command no
longer needs to know that it&amp;rsquo;s being used in a pipeline: whatever flows
through the pipe is passed transparently via the first argument to the
function call. This has made pipes more useful, and usable in more
situations.&lt;/p&gt;
&lt;p&gt;Macros can still know whether there exist a pipe argument, which can
make for some interesting constructs. Consider this variant of the
&lt;code&gt;foreach&lt;/code&gt; macro, which can &amp;ldquo;hang off&amp;rdquo; the end of a pipe:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[&amp;quot;1&amp;quot; &amp;quot;2&amp;quot; &amp;quot;3&amp;quot;] | foreach { |x| echo $x }
--&amp;gt; 1
--&amp;gt; 2
--&amp;gt; 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not sure if this variant is useful, but I think it could be. It seems
like a natural way to iterate items passed through the pipe. I&amp;rsquo;m
wondering if this could extend to the &lt;code&gt;if&lt;/code&gt; macro as well, but that
variant might not be as natural to read.&lt;/p&gt;
&lt;p&gt;Another simplification was changing the &lt;code&gt;map&lt;/code&gt; builtin to accept
anonymous blocks, as well as an &amp;ldquo;invokable&amp;rdquo; commands by name.
Naturally, this also works with pipes too:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[a b c] | map { |x| toUpper $x }
--&amp;gt; [A B C]

[a b c] | map toUpper
--&amp;gt; [A B C]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As for other language features, I finally got around to adding support
for integer literals. They look pretty much how you expect:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set n 123
echo $n
--&amp;gt; 123
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One side effect of this is that an identifier can no longer start with a
dash followed by a digit, as that would be parsed as the start of a
negative integer. This probably isn&amp;rsquo;t a huge deal, but it could affect
command switches, which are essentially just identifiers that start with
a dash.&lt;/p&gt;
&lt;p&gt;Most of the other work done was behind the scenes trying to make UCL
easier to embed. I added the notion of &amp;ldquo;listable&amp;rdquo; and &amp;ldquo;hashable&amp;rdquo;
proxies objects, which allow the UCL user to treat a Go slice or a Go
struct as a list or hash respectively, without the embedder doing
anything other than return them from a function (I&amp;rsquo;ve yet to add this
support to maps just yet).&lt;/p&gt;
&lt;p&gt;A lot of the native API is still a huge mess, and I really need to tidy
it up before I&amp;rsquo;d be comfortable opening the source. Given that the
language is pretty featureful now to be useful, I&amp;rsquo;ll probably start
working on this next. Plus adding builtins. Really need to start adding
useful builtins.&lt;/p&gt;
&lt;p&gt;Anyway, more to come on this topic I&amp;rsquo;m sure.&lt;/p&gt;
&lt;p&gt;Oh, one last thing: I&amp;rsquo;ve put together an online playground where you
can try the language out in the browser. It&amp;rsquo;s basically a WASM build of
the language running in a &lt;a href=&#34;https://xtermjs.org&#34;&gt;JavaScript terminal emulator&lt;/a&gt;. It was a
little bit of a rush job and there&amp;rsquo;s no reason for building this other
than it being a fun little thing to do.&lt;/p&gt;
&lt;p&gt;You can &lt;a href=&#34;https://ucl.lmika.dev/&#34;&gt;try it out here&lt;/a&gt;, if you&amp;rsquo;re curious.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Simplifying UCL</title>
      <link>https://lmika.org/2024/04/23/simplifying-ucl.html</link>
      <pubDate>Tue, 23 Apr 2024 09:21:44 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2024/04/22/simplifying-ucl.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been using UCL for several days now in that work tool I mentioned,
and I&amp;rsquo;m wondering if the technical challenge that comes of making a
featureful language is crowding out what I set out to do: making a
useful command language that is easy to embed.&lt;/p&gt;
&lt;p&gt;So I&amp;rsquo;m thinking of making some simplifications.&lt;/p&gt;
&lt;p&gt;The first is to expand the possible use of pipes. To date, the only
thing that can travel through pipes are streams. But many of the
commands I&amp;rsquo;ve been adding simply return slices. This is probably
because there&amp;rsquo;s currently no &amp;ldquo;stream&amp;rdquo; type available to the embedder,
but even if there was, I&amp;rsquo;m wondering if it make sense to allow the
embedder to pass slices, and other types, through pipes as well.&lt;/p&gt;
&lt;p&gt;So, I think I&amp;rsquo;m going to take a page out of Go&amp;rsquo;s template book and
simply have pipes act as syntactic sugar over sequential calls. The goal
is to make the construct &lt;code&gt;a | b&lt;/code&gt; essentially be the same as &lt;code&gt;b (a)&lt;/code&gt;,
where the first argument of &lt;code&gt;b&lt;/code&gt; will be the result of &lt;code&gt;a&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As for streams, I&amp;rsquo;m thinking of removing them as a dedicated object
type. Embedders could certainly make analogous types if they need to,
and the language should support that, but the language will no longer
offer first class support for them out of the box. &lt;/p&gt;
&lt;p&gt;The second is to remove any sense of &amp;ldquo;purity&amp;rdquo; of the builtins. You may
recall the indecision I had regarding using anonymous procs with the
&lt;code&gt;map&lt;/code&gt; command:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I&amp;rsquo;m not sure how I can improve this. I don&amp;rsquo;t really want to add
automatic dereferencing of identities: they&amp;rsquo;re very useful as
unquoted string arguments. I suppose I could add another construct
that would support dereferencing, maybe by enclosing the identifier in
parenthesis.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I think this is the wrong way to think of this. Again, I&amp;rsquo;m not here to
design a pure implementation of the language. The language is meant to
be easy to use, first and foremost, in an interactive shell, and if that
means sacrificing purity for a &lt;code&gt;map&lt;/code&gt; command that supports blocks,
anonymous procs, and automatic dereferencing of commands just to make it
easier for the user, then I think that&amp;rsquo;s a trade work taking.&lt;/p&gt;
&lt;p&gt;Anyway, that&amp;rsquo;s the current thinking as of now.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>UCL: First Embed, and Optional Arguments</title>
      <link>https://lmika.org/2024/04/18/ucl-first-embed.html</link>
      <pubDate>Thu, 18 Apr 2024 09:39:12 +1100</pubDate>
      
      <guid>http://lmika.micro.blog/2024/04/17/ucl-first-embed.html</guid>
      <description>&lt;p&gt;Came up with a name: Universal Control Language: UCL. See, you have TCL;
but what if instead of being used for tools, it can be more universal?
Sounds so much more… universal, am I right? 😀&lt;/p&gt;
&lt;p&gt;Yeah, okay. It&amp;rsquo;s not a great name. But it&amp;rsquo;ll do for now.&lt;/p&gt;
&lt;p&gt;Anyway, I&amp;rsquo;ve started integrating this language with the admin tool I&amp;rsquo;m
using at work. This tool I use is the impetus for this whole endeavour.
Up until now, this tool was just a standard CLI command usable from the
shell. But it&amp;rsquo;s not uncommon for me to have to invoke the tool multiple
times in quick succession, and each time I invoke it, it needs to
connect to backend systems, which can take a few seconds. Hence the
reason why I&amp;rsquo;m converting it into a REPL.&lt;/p&gt;
&lt;p&gt;Anyway, I added UCL to the tool, along with a &lt;a href=&#34;https://github.com/chzyer/readline&#34;&gt;readline library&lt;/a&gt;, and
wow, did it feel good to use. So much better than the simple quote-aware
string splitter I&amp;rsquo;d would&amp;rsquo;ve used. And just after I added it, I got a
flurry of requests from my boss to gather some information, and although
the language couldn&amp;rsquo;t quite handle the task due to missing or
unfinished features, I can definitely see the potential there.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m trying my best to only use what will eventually be the public API
to add the tool-specific bindings. The biggest issue is that these
&amp;ldquo;user bindings&amp;rdquo; (i.e. the non-builtins) desperately need support for
producing and consuming streams. They&amp;rsquo;re currently producing Go slices,
which are being passed around as opaque &amp;ldquo;proxy objects&amp;rdquo;, but these
can&amp;rsquo;t be piped into other commands to, say, filter or map. Some other
major limitations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No commands to actually filter or map. In fact, the whole standard
library needs to be built out.&lt;/li&gt;
&lt;li&gt;No ability to get fields from hashes or lists, including proxy objects
which can act as lists or hashes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One last thing that would be nice is the ability to define optional
arguments. I actually started work on that last night, seeing that it&amp;rsquo;s
relatively easy to build. I&amp;rsquo;m opting for a style that looks like the
switches you&amp;rsquo;d find on the command line, with option names starting
with dashes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;join &amp;quot;a&amp;quot; &amp;quot;b&amp;quot; -separator &amp;quot;,&amp;quot; -reverse
--&amp;gt; b, a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each option can have zero or more arguments, and boolean options can be
represented as just having the switch. This does mean that they&amp;rsquo;d have
to come after the positional arguments, but I think I can live with
that.  Oh, and no syntactic sugar for single-character options: each
option must be separated by whitespace (the grammar actually treats them
as identifiers). In fact, I&amp;rsquo;d like to discourage the use of
single-character option names for these: I prefer the clarity that comes
from having the name written out in full (that said, I wouldn&amp;rsquo;t rule
out support for aliases). This eliminates the need for double dashes, to
distinguish long option names from a cluster of single-character
options, so only the single dash will be used.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll talk more about how the Go bindings look later, after I&amp;rsquo;ve used
them a little more and they&amp;rsquo;re a little more refined.&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>