<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Peter Shinners</title>
    <description>The latest articles on DEV Community by Peter Shinners (@shredwheat).</description>
    <link>https://dev.to/shredwheat</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2639173%2Fe54ce1f2-f591-445e-a45e-a642db80a523.jpg</url>
      <title>DEV Community: Peter Shinners</title>
      <link>https://dev.to/shredwheat</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shredwheat"/>
    <language>en</language>
    <item>
      <title>Comp Language Tags</title>
      <dc:creator>Peter Shinners</dc:creator>
      <pubDate>Fri, 03 Apr 2026 04:17:35 +0000</pubDate>
      <link>https://dev.to/shredwheat/comp-language-tags-bga</link>
      <guid>https://dev.to/shredwheat/comp-language-tags-bga</guid>
      <description>&lt;p&gt;Comp allows defining a hierarchy of named values that can be used anywhere in the namespace. These are called tags and have several useful properties.&lt;/p&gt;

&lt;p&gt;Comp uses tags almost like keywords throughout the language. The builtin boolean types &lt;code&gt;true&lt;/code&gt; are and &lt;code&gt;false&lt;/code&gt; are just regular tags. Even flow control statements like &lt;code&gt;skip&lt;/code&gt; and &lt;code&gt;stop&lt;/code&gt; (known as &lt;code&gt;continue&lt;/code&gt; and &lt;code&gt;break&lt;/code&gt; in many other languages) are just tags.&lt;/p&gt;

&lt;p&gt;Tags are defined in a module as a simple hierarchy. Hierarchies from other modules can be extended within an internal module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="n"&gt;severity&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="n"&gt;high&lt;/span&gt; &lt;span class="n"&gt;medium&lt;/span&gt; &lt;span class="n"&gt;low&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="n"&gt;comp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="n"&gt;maybe&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Comp namespaces work in that any definition can be referenced by its fully qualified name or as just the leaf portion of the name that is non ambiguous. So &lt;code&gt;maybe&lt;/code&gt; works just as well as &lt;code&gt;bool.maybe&lt;/code&gt; inside of our namespace.&lt;/p&gt;

&lt;p&gt;In this case we've extended bool with our own crazy value. But the original module has no knowledge of our extensions. This allows us to extend but not pollute tag hierarchies.&lt;/p&gt;

&lt;p&gt;There's a mountain of other details. Tags are the quick and easy way to avoid strings to define types or behaviors. A list of other places tags have an influence on the language.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tags are used to define units, which we've already seen in values like &lt;code&gt;24#second&lt;/code&gt; or &lt;code&gt;"select verion()"#sql&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Tags have a high precedence when morphing structs to shapes, something to demonstrate in a future post.

&lt;ul&gt;
&lt;li&gt;This has a profoundly useful impact on assigning parameters to function calls.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Tags are both shapes and singleton values, which gives them a dual role.&lt;/li&gt;

&lt;li&gt;Tags from unknown modules can be serialized and used as a "raw tag", which can be promote later given a module that can define them. &lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>comp</category>
    </item>
    <item>
      <title>Comp Language Numbers</title>
      <dc:creator>Peter Shinners</dc:creator>
      <pubDate>Thu, 02 Apr 2026 04:56:31 +0000</pubDate>
      <link>https://dev.to/shredwheat/comp-language-numbers-2d8l</link>
      <guid>https://dev.to/shredwheat/comp-language-numbers-2d8l</guid>
      <description>&lt;p&gt;Comp's number values are not restricted to traditional hardware representations and their shortcomings. Comp numbers have huge, open ended precision with mathematical operations that do not accumulate errors. A single &lt;code&gt;~num&lt;/code&gt; type that represents all possible numbers.&lt;/p&gt;

&lt;p&gt;This is somewhat of a game changer for writing code. It feels surprisingly futuristic to do things like convert between Farenheit to Celsius then back and end up with the exact same number you started with. No "approximate" results here. &lt;/p&gt;

&lt;p&gt;It should make you wonder why anyone must tolerate &lt;code&gt;(1/3)*3 != 1.0&lt;/code&gt; or rounding &lt;code&gt;256.49999&lt;/code&gt; to &lt;code&gt;257&lt;/code&gt; in the year 2026? There is an excellent reason to tolerate these inaccuracies; Computers are astonishingly fast and efficient at storing and computing numbers. But I get the sense mostly it's because of decades of tolerating and being forced to accept. &lt;/p&gt;

&lt;p&gt;When those come into play the language will use allocated of arrays of numbers; much like the amazing Numpy which makes storage and computation of numbers more tasteful in Python.&lt;/p&gt;

&lt;p&gt;When interacting with legacy languages it is still useful to define numbers in terms they can understand. This is one area where Comp's limits shine brightly. I'll cover limits more in a future post, but the quick definition is that limits can be placed on defined types. A quick shape definition creates a type that can't overflow or allow lossy conversion.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt; &lt;span class="n"&gt;uint8&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt; &lt;span class="n"&gt;ge&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll get deeper into shape definitions later. The language does provide functions that handle lossy conversions in specific ways, and it's easy to write your own.&lt;/p&gt;

&lt;p&gt;Comp numbers are not allowed to be illegal values (&lt;code&gt;inf&lt;/code&gt; or &lt;code&gt;nan&lt;/code&gt;) by default. But those can be allowed with union types where desirable.&lt;/p&gt;

&lt;p&gt;I highly recommend Julia Evan's article that explains the how and whys of problems that will never be a problem for Comp developers.&lt;br&gt;
&lt;a href="https://jvns.ca/blog/2023/01/13/examples-of-floating-point-problems/" rel="noopener noreferrer"&gt;https://jvns.ca/blog/2023/01/13/examples-of-floating-point-problems/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>coding</category>
      <category>computerscience</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Comp Language Struct</title>
      <dc:creator>Peter Shinners</dc:creator>
      <pubDate>Wed, 01 Apr 2026 05:59:25 +0000</pubDate>
      <link>https://dev.to/shredwheat/comp-language-struct-5j6</link>
      <guid>https://dev.to/shredwheat/comp-language-struct-5j6</guid>
      <description>&lt;p&gt;An ongoing series of my thoughts and ideas for my Comp programming language.&lt;/p&gt;

&lt;p&gt;Comp provides a single container type. It's a flexible container that combines both ordered and named fields in a unique style. A struct literal is defined by a series of fields in side of curly braces. Named and unnamed fields can be mixed freely, while always remaining ordered. Field values can be mixed and matched with any types. All data in Comp is immutable, including these structures. &lt;/p&gt;

&lt;p&gt;One way to think of this is similar to how Python arguments are defined for a function. Some arguments are positional and some arguments are named. When combined with Comp's shape values we get defaults and flexible morphing (casts). This makes Comp's structs work like Python arguments, but you don't need to invoke a function to assemble them.&lt;/p&gt;

&lt;p&gt;Some examples likely make this clearer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"cat"&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Joe"&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;warning&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"it did not work"&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"car"&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2021&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"bike"&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2025&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember, Comp's syntax uses no separators and whitespace is arbitrary. These statements could be split over multiple lines, joined, or justified in whatever style felt appropriate.&lt;/p&gt;

&lt;p&gt;Fields are accessed either with dotted field name or positionally using a special index field. All fields can be referenced by index, which works for both named and unnamed fields. And the first index starts at 0, this does not allow "negative indexing" from the back of the container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;vehicles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Typical field names are simple text tokens, which support &lt;code&gt;kebab-case&lt;/code&gt;. But any value can be used as a field name, including numbers, tags, and other structures. These "value" field named are wrapped in single quotes and allow any value or expression. Double quotes can be used as text when the field name isn't a valid token. These same rules are used for defining fields and referencing fields. There are few other "advanced field lookup" syntaxes but these ones go a long way.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;  &lt;span class="s"&gt;"Server Port"&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;12345&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="s"&gt;"Server Port"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>comp</category>
    </item>
    <item>
      <title>Comp Language Syntax</title>
      <dc:creator>Peter Shinners</dc:creator>
      <pubDate>Tue, 31 Mar 2026 04:26:55 +0000</pubDate>
      <link>https://dev.to/shredwheat/comp-language-syntax-1ca0</link>
      <guid>https://dev.to/shredwheat/comp-language-syntax-1ca0</guid>
      <description>&lt;p&gt;An ongoing series in my quest to untangle my own thoughts and goals for the Comp programming language.&lt;/p&gt;

&lt;p&gt;A language focused on developer experience? So much of my focus has been on the syntax and grammar. The entire concept is built on a handful of core fundamental rules that everything expands from.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No separators or terminators&lt;/li&gt;
&lt;li&gt;Whitespace independent

&lt;ul&gt;
&lt;li&gt;No line-based statements&lt;/li&gt;
&lt;li&gt;No indentation&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Along with these fundamentals there are a few other strongly motivated designs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;kabab-case&lt;/code&gt; for identifiers&lt;/li&gt;
&lt;li&gt;No keywords&lt;/li&gt;
&lt;li&gt;Avoid nesting braces&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Along with that there is has been from-the-start requirement that the structure literal has two forms.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;{1 2 3}&lt;/code&gt; for positional sequences (lists, arrays)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{a=1 b=2}&lt;/code&gt; for named mappings (dicts, hashes)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This has been a long and ongoing puzzle, but the payoff has been spectacular. Let's look at another small code example and call out a few highlights.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;!&lt;/span&gt;func shopping-cart-demo &lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"Apple"&lt;/span&gt; &lt;span class="nv"&gt;price&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.00&lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"Banana"&lt;/span&gt; &lt;span class="nv"&gt;price&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.50 &lt;span class="nv"&gt;quantity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2&lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"Apple"&lt;/span&gt; 1.00 &lt;span class="nv"&gt;quantity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2&lt;span class="o"&gt;}&lt;/span&gt;  // replace previous apples
  &lt;span class="o"&gt;}&lt;/span&gt;
  | reduce :&lt;span class="o"&gt;(&lt;/span&gt;| upsert :&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$.&lt;/span&gt;name&lt;span class="o"&gt;))&lt;/span&gt;
  | cart-total
  | output &lt;span class="s2"&gt;"Total: %()"&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Keywords use a &lt;code&gt;!&lt;/code&gt; prefix. This makes them a bit noisier than I'd like, but it's not a bad design to make them pronounced. This also allows freely introducing new keywords in the future.&lt;/li&gt;
&lt;li&gt;Whitespace independence means this entire definition could be placed on a single line, or each statement split or joined as the author decides is most readable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's a history of experiments, compromises, and undesirable workarounds to assemble these pieces. Much of this time I wasn't sure these constraints could even be appeased.&lt;/p&gt;

&lt;p&gt;I've been using the &lt;a href="https://github.com/lark-parser/lark" rel="noopener noreferrer"&gt;Lark&lt;/a&gt; library to handle parsing. I'd never experimented with it before, but now have a good deal of experience stretching it's LALR rules. This gives an ideal O(n) performance. I have been surprised at the cost of building the grammar at runtime. Fortunately the library is quite prepared for this and comes with some high level caching options.&lt;/p&gt;

</description>
      <category>comp</category>
    </item>
    <item>
      <title>Comp the Language</title>
      <dc:creator>Peter Shinners</dc:creator>
      <pubDate>Sun, 29 Mar 2026 22:42:38 +0000</pubDate>
      <link>https://dev.to/shredwheat/comp-the-language-1ifd</link>
      <guid>https://dev.to/shredwheat/comp-the-language-1ifd</guid>
      <description>&lt;p&gt;I've been brewing on ideas for a new programming language for months now. That's nothing anybody should need to notice, I see three new language announcements a day on various Reddit channels.&lt;/p&gt;

&lt;p&gt;Perhaps tinkering with a new language is folly; a new programming language in 2026? The dawn of AI coding is eminent, so who is looking at programming languages?&lt;/p&gt;

&lt;p&gt;Well, I do it because it captivates me. It is my itch these days, and therefore, I scratch. Perhaps I will soon learn the reasons why more languages isn't best languages. Perhaps this will become the new Coffeescript for Python. Perhaps this will become the new Python itself. In reality, no. This is a project by myself for myself.&lt;/p&gt;

&lt;p&gt;So why even share? Posting and describing the language should help my organize thoughts and ideas. There's nothing like having to explain a process to shine a flashlight on the weakest links, and potentially the greatest links.&lt;/p&gt;

&lt;p&gt;It's also folly to be thinking a new programming language will discover anything new or revolutionary. There are hundreds of amazing languages and libraries created by smarter people than myself. At some point additional perspectives will help, if not for the potential language, at least for my own expectations.&lt;/p&gt;

&lt;p&gt;Project links? Example code? That must wait. For now I'll leave the most minimal of examples behind. Details must wait for future posts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;!&lt;/span&gt;func greetings ~nil &lt;span class="o"&gt;(&lt;/span&gt;
   &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"USERNAME"&lt;/span&gt; &lt;span class="s2"&gt;"USER"&lt;/span&gt; &lt;span class="s2"&gt;"LOGNAME"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
   | map :&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;| get-env |? skip&lt;span class="o"&gt;)&lt;/span&gt;
   | first &lt;span class="nv"&gt;or&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"World"&lt;/span&gt;
   | output &lt;span class="s2"&gt;"Hello, %()!"&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>comp</category>
    </item>
    <item>
      <title>Monkey AIslands - Part 1</title>
      <dc:creator>Peter Shinners</dc:creator>
      <pubDate>Tue, 03 Feb 2026 05:41:31 +0000</pubDate>
      <link>https://dev.to/shredwheat/monkey-aislands-part-1-46fm</link>
      <guid>https://dev.to/shredwheat/monkey-aislands-part-1-46fm</guid>
      <description>&lt;p&gt;In the legendary &lt;a href="https://en.wikipedia.org/wiki/The_Secret_of_Monkey_Island" rel="noopener noreferrer"&gt;Secret of Monkey Island&lt;/a&gt;, one of the puzzles is to assemble an arsenal of witty insults and devastating comebacks to use during sword fights. Some say the wit is mightier than the sword.&lt;/p&gt;

&lt;p&gt;I've decided to see how well various modern LLMs perform at matching the appropriate comebacks to these classic adventure game challenges.&lt;/p&gt;

&lt;p&gt;A fully accomplished sword fighter will know 16 different insults and their responses. To add difficulty to this comparison I've added 4 generic comebacks that do not pair to any insult.&lt;/p&gt;

&lt;p&gt;If this pinnacle of computerized entertainment predates your lifespan by decades, you can still find reasonably recent versions on &lt;a href="https://store.steampowered.com/app/32360/The_Secret_of_Monkey_Island_Special_Edition/" rel="noopener noreferrer"&gt;Steam&lt;/a&gt;, &lt;a href="https://www.gog.com/en/game/the_secret_of_monkey_island_special_edition" rel="noopener noreferrer"&gt;GoG&lt;/a&gt;, and likely other digital retailers.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Prompt
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Given this list of 16 insults and 20 witty insults, match the best response to each challenge. Notice there are several generic responses that will be unused in the final answers. List orders are randomized. These are from a classic, light-hearted video game related to pirates and sword fighting.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In hindsight, I see I added unintential challenge by mis-wording my prompt. Carry on LLMs!&lt;/p&gt;




&lt;h2&gt;
  
  
  The Insults
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[spoilers]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Soon you'll be wearing my sword like a shish kebab!&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;First you'd better stop waving it like a feather-duster.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;There are no words for how disgusting you are.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Yes, there are. You just never learned them.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;My handkerchief will wipe up your blood!&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;So you got that job as janitor, after all.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;You fight like a dairy farmer.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;How appropriate. You fight like a cow.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;This is the END for you, you gutter-crawling cur!&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;And I've got a little TIP for you, get the POINT?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Nobody's ever drawn blood from me and nobody ever will.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;You run THAT fast?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;People fall at my feet when they see me coming.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Even BEFORE they smell your breath?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;I've heard you were a contemptible sneak.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Too bad no one's ever heard of YOU at all.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;You're no match for my brains, you poor fool.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;I'd be in real trouble if you ever used them.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;You make me want to puke.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;You make me think somebody already did.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Have you stopped wearing diapers yet?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Why, did you want to borrow one?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;You have the manners of a beggar.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;I wanted to make sure you'd feel comfortable with me.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;I'm not going to take your insolence sitting down!&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Your hemorrhoids are flaring up again, eh?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;I got this scar on my face during a mighty struggle!&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;I hope now you've learned to stop picking your nose.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;I've spoken with apes more polite then you.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;I'm glad to hear you attended your family reunion.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;I once owned a dog that was smarter then you.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;He must have taught you everything you know.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The unused responses that I added are&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Then get ready to feel the thunder.&lt;/li&gt;
&lt;li&gt;I've already taken liberties with your mother.&lt;/li&gt;
&lt;li&gt;Not before you FACE my wrath.&lt;/li&gt;
&lt;li&gt;Fortunately, I've been preparing my whole life.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Responses
&lt;/h2&gt;

&lt;h3&gt;
  
  
  GPT-4.1
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Matching Score 14/16&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here are the classic insult-comeback pairs from the pirate sword-fighting game "The Secret of Monkey Island." Each insult is matched with its best witty response. Some comebacks are generic and may fit more than one insult, but these are the canonical matches from the game. Let me know if you want the pairs in a different format!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Correctly identified these were from Secret of Monkey Island, then proceeded to get a few wrong. It reused some of the responses multiple times.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Missed responses&lt;/u&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Soon you'll be wearing my sword like a shish kebab!&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;How appropriate. You fight like a cow.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;There are no words for how disgusting you are.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;I'm glad to hear you attended your family reunion.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  GPT-5.1
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Score 16/16&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Minimal and correct response.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here are the best matches:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  GPT-5.2
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Score 16/16&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Least helpful response of generating a table containing numbers to answer numbers. It really put a lot of work into these answers, definitely on the slower of the group. No summary or response other than the the resulting answers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Claude Haiku 4.5
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Score 0/16&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I appreciate the message, but I need to let you know that this request isn't related to programming. The insult-and-comeback matching task appears to be from "The Secret of Monkey Island," a classic adventure game. While it's a fun puzzle, it falls outside what I'm designed to help with as your AI programming assistant.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What good can my coding assistant be if it can't match rapier wits with the code I may come across?&lt;/p&gt;

&lt;h3&gt;
  
  
  Claude Sonnet 4.5
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Score 16/16&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is from "The Secret of Monkey Island"! Here are the matched insult-comeback pairs:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Aha, this was one of the few (only?) models to choose one of my generic zinger answers. It managed to miss a few others on its own. But I do appreciate it's enthusiasm for recognizing the source of the material.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Missed responses&lt;/u&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Soon you'll be wearing my sword like a shish kebab!&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;And I've got a little TIP for you, get the POINT?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;This is the END for you, you gutter-crawling cur!&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Not before you FACE my wrath.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Claude Opus 4.5
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Score 16/16&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Looking at these classic Monkey Island insult sword fighting exchanges, here are the matched pairs:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Quick and accurate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Grok Code Fast
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Score 11/16&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not a strong showing, this really does fight like a dairy farmer. No additional notes or output, just the straight answers.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Missed Responses&lt;/u&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;My handkerchief will wipe up your blood!&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Why, did you want to borrow one?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;This is the END for you, you gutter-crawling cur!&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Not before you FACE my wrath.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Have you stopped wearing diapers yet?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;I hope now you've learned to stop picking your nose.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;You have the manners of a beggar.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;So you got that job as janitor, after all.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;I got this scar on my face during a mighty struggle!&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;And I've got a little TIP for you, get the POINT?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Gemini 2.5 Pro
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Score 16/16&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here are the correct pairings for the insults and comebacks:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;All exactly correct answers with a minimal commentary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gemini 3 Flash
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Score 16/16&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here are the matched insults and comebacks from the classic Monkey Island series:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the only model that showed the 4 unused answers after showing its choices for each insult.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gemini 3 Pro
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Score 16/16&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here are the correct matches for the Insult Sword Fighting exchanges from The Secret of Monkey Island:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yes. All the Gemini models I tested performed excellently.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Summary
&lt;/h2&gt;

&lt;p&gt;Many of the models perfectly matched the insults and most correctly identified this material comes from the game, The Secret of Monkey Island. I guess the tie breaker then comes down to the summary, commentary, and formatting generated by the LLM.&lt;/p&gt;

&lt;p&gt;Part of me wonders how much "thought" went into these answers, versus potentially being baked into the general body of knowledge of each model?&lt;/p&gt;

&lt;h3&gt;
  
  
  Best
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Gemini 3 Flash&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While several got perfect answers and formatted the results nicely, this wins by using the "least tokens multiplier for me in VSCode. I also felt it provided the most comprehensive answer. Well done Gemini.&lt;/p&gt;

&lt;h3&gt;
  
  
  Worst
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Grok Code Fast&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One could argue this did better than Haiku, but in this case I'd rather be called crazy than lied to.&lt;/p&gt;

</description>
      <category>ai</category>
    </item>
    <item>
      <title>Colors with Rio's oklab color space</title>
      <dc:creator>Peter Shinners</dc:creator>
      <pubDate>Mon, 03 Feb 2025 05:59:31 +0000</pubDate>
      <link>https://dev.to/shredwheat/colors-with-rios-oklab-color-space-52fb</link>
      <guid>https://dev.to/shredwheat/colors-with-rios-oklab-color-space-52fb</guid>
      <description>&lt;p&gt;While browsing the Rio source I noticed it &lt;a href="https://github.com/rio-labs/rio/blob/main/rio/color.py" rel="noopener noreferrer"&gt;manages colors &lt;/a&gt; in the &lt;a href="https://bottosson.github.io/posts/oklab/" rel="noopener noreferrer"&gt;Oklab color space&lt;/a&gt; which I hadn't heard of. I also wasn't expecting the technique it used in the &lt;code&gt;Color.brighter&lt;/code&gt; and &lt;code&gt;Color.darker&lt;/code&gt; methods.&lt;/p&gt;

&lt;p&gt;I've &lt;a href="https://dev.to/shredwheat/minimal-rio-intro-1hpm"&gt;been impressed with Rio in the past &lt;/a&gt; for allowing minimal Python code to create user interfaces. Curious with how these color operations felt in practice, I created a &lt;a href="https://github.com/PeterShinners/rioquicklooks/blob/colors/colors.py" rel="noopener noreferrer"&gt;quick 50 line demo&lt;/a&gt; to interact with a simple color wheel.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/1052906026" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;It looks like the Oklab color space excels at color gradients by giving a natural range through each hue. Unfortunately I don't immediately like how Rio is adjusting brightness with these methods. In the video, see how the outer light colors change through their range of brightness separately from the inner dark colors. This means &lt;code&gt;Color.lighter(0.1)&lt;/code&gt; will have a drastic affect on dark colors and minimal change to lighter colors. This could still be a desirable quality, so I'm unwilling declare this as good or bad. &lt;/p&gt;

&lt;p&gt;Separately; points to Rio once again for making small and lightweight tools fun to develop. The community has been lightning quick on my wild questions and ideas. Also points to Oklab for their impressive gradient examples.&lt;/p&gt;

</description>
      <category>python</category>
      <category>rio</category>
      <category>color</category>
      <category>ui</category>
    </item>
    <item>
      <title>Windows dotted paths</title>
      <dc:creator>Peter Shinners</dc:creator>
      <pubDate>Sun, 05 Jan 2025 01:19:32 +0000</pubDate>
      <link>https://dev.to/shredwheat/windows-dotted-paths-4pfj</link>
      <guid>https://dev.to/shredwheat/windows-dotted-paths-4pfj</guid>
      <description>&lt;p&gt;I stumbled into learning that Windows (or NTFS?) does not allow filenames with trailing dots.&lt;/p&gt;

&lt;p&gt;Internally it appearsthe dot is a separator between the base filename and the extension. Some tools treat the final dot as implied, so &lt;code&gt;type plain.&lt;/code&gt; will show the contents of a file named &lt;code&gt;plain&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Armed with this curiosity I decided to create a troublesome git repository to discover how Windows would treat such a thing?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Indiscriminate error?&lt;/li&gt;
&lt;li&gt;Pick one arbitrary conflicting name?&lt;/li&gt;
&lt;li&gt;Privilege escalation?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://github.com/PeterShinners/doomdots" rel="noopener noreferrer"&gt;https://github.com/PeterShinners/doomdots&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;PS C:&lt;span class="se"&gt;\d&lt;/span&gt;ev&amp;gt; git clone https://github.com/PeterShinners/doomdots.git
Cloning into &lt;span class="s1"&gt;'doomdots'&lt;/span&gt;...
remote: Enumerating objects: 35, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Counting objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;35/35&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Compressing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;24/24&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Total 35 &lt;span class="o"&gt;(&lt;/span&gt;delta 10&lt;span class="o"&gt;)&lt;/span&gt;, reused 0 &lt;span class="o"&gt;(&lt;/span&gt;delta 0&lt;span class="o"&gt;)&lt;/span&gt;, pack-reused 0 &lt;span class="o"&gt;(&lt;/span&gt;from 0&lt;span class="o"&gt;)&lt;/span&gt;
Receiving objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;35/35&lt;span class="o"&gt;)&lt;/span&gt;, 10.41 KiB | 1.16 MiB/s, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Resolving deltas: 100% &lt;span class="o"&gt;(&lt;/span&gt;10/10&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
error: invalid path &lt;span class="s1"&gt;'MIXed.'&lt;/span&gt;
fatal: unable to checkout working tree
warning: Clone succeeded, but checkout failed.
You can inspect what was checked out with &lt;span class="s1"&gt;'git status'&lt;/span&gt;
and retry with &lt;span class="s1"&gt;'git restore --source=HEAD :/'&lt;/span&gt;

PS C:&lt;span class="se"&gt;\d&lt;/span&gt;ev&amp;gt; &lt;span class="nb"&gt;cd&lt;/span&gt; .&lt;span class="se"&gt;\d&lt;/span&gt;oomdots&lt;span class="se"&gt;\&lt;/span&gt;
PS C:&lt;span class="se"&gt;\d&lt;/span&gt;ev&amp;gt; git switch main
error: invalid path &lt;span class="s1"&gt;'MIXed.'&lt;/span&gt;
error: invalid path &lt;span class="s1"&gt;'enddot.'&lt;/span&gt;
error: invalid path &lt;span class="s1"&gt;'extdot.txt.'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's likely these errors come from Git itself, and there's an alternative where it could fallback on some undefined system behavior.&lt;/p&gt;

&lt;p&gt;Anyways, one more corner case to avoid along with mixed case naming conflicts and invalid characters.&lt;/p&gt;

</description>
      <category>git</category>
      <category>fail</category>
      <category>windows</category>
    </item>
    <item>
      <title>Minimal Rio Intro</title>
      <dc:creator>Peter Shinners</dc:creator>
      <pubDate>Fri, 03 Jan 2025 03:05:56 +0000</pubDate>
      <link>https://dev.to/shredwheat/minimal-rio-intro-1hpm</link>
      <guid>https://dev.to/shredwheat/minimal-rio-intro-1hpm</guid>
      <description>&lt;p&gt;In early November I saw a release announcement for Rio (&lt;a href="https://rio.dev" rel="noopener noreferrer"&gt;https://rio.dev&lt;/a&gt;), an upcoming Python library for creating user interfaces. I have years of experience using Qt with Python and always interested in seeing new approaches.&lt;/p&gt;

&lt;p&gt;I went through the &lt;em&gt;Tic Tac Toe&lt;/em&gt; tutorial and found a lot of things I liked. I was initially impressed by the simplicity of writing interfaces using component classes. The interface runs through an HTML document, which is completely encapsulated by the library. This gives many possibilities on how and where Rio applications are run. Rio optionally includes a standalone webview application. However, I critically disliked the included &lt;code&gt;rio&lt;/code&gt; command line tool and the initial project structure it creates. &lt;/p&gt;

&lt;p&gt;I think Rio deserves a lighter weight tutorial that strips the boilerplate and abstractions to show the potential this library has. Let's start from nothing and discover how Rio feels building it up for ourselves. I found getting started with &lt;code&gt;uv&lt;/code&gt; to be as simple as I'd hoped.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv init minirio &lt;span class="nt"&gt;--no-readme&lt;/span&gt; &lt;span class="nt"&gt;--no-pin-python&lt;/span&gt; &lt;span class="nt"&gt;--vcs&lt;/span&gt; none
&lt;span class="nb"&gt;cd &lt;/span&gt;minirio
uv add rio-ui[window]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The optional &lt;code&gt;[window]&lt;/code&gt; feature installs the many dependencies needed to run the standalone app. Also be aware I needed to use &lt;code&gt;==9.3&lt;/code&gt; on Windows due to missing pyside builds.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's use the minimal code needed to build this application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fas9efy86bfjvwtd890ht.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fas9efy86bfjvwtd890ht.jpg" alt="Image description" width="400" height="196"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;rio&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;World&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;rio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;material/star&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;align_x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;align_y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;rio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello, **&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;**&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;align_y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run_in_window&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a regular Python script. Run it with your python interpreter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run hello.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A component is little more than a &lt;code&gt;build&lt;/code&gt; method that returns a component and a state defined on the class. You do not define &lt;code&gt;__init__&lt;/code&gt; or other typical boilerplate. You can replace the &lt;code&gt;run_in_window&lt;/code&gt; with a &lt;code&gt;run_as_web_server&lt;/code&gt; and interact with this application in your browser.&lt;/p&gt;

&lt;p&gt;It takes very little to add some interactivity. Here is a similar component that adds a checkbox and styling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;gradient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LinearGradientFill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PINK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Greeting2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;style&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TextStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fill&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;gradient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;rio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Checkbox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;is_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;rio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Roses are red.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is using &lt;code&gt;self.bind()&lt;/code&gt; to create a two-way binding between the checkbox state and an attribute. Alternatively, it is straightforward to assign the checkbox's &lt;code&gt;on_change&lt;/code&gt; argument to any method and change attributes of &lt;code&gt;self&lt;/code&gt; as desired.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0matkwj5utr15xayw2fw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0matkwj5utr15xayw2fw.jpg" alt="Image description" width="586" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Find more complete examples and documentation on the Rio project website. Personally, I'm not yet ready to leave the world of Qt and Pyside, but I also think there's enough in Rio to keep an eye on.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://rio.dev/examples" rel="noopener noreferrer"&gt;https://rio.dev/examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rio.dev/docs" rel="noopener noreferrer"&gt;https://rio.dev/docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rio-labs/rio" rel="noopener noreferrer"&gt;https://github.com/rio-labs/rio&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>ui</category>
    </item>
  </channel>
</rss>
